From d6db3ef09fa8b403ae9b6742b46c87adae11a6dd Mon Sep 17 00:00:00 2001 From: Sami Mazouz Date: Mon, 4 Nov 2024 18:22:00 +0100 Subject: [PATCH] docs: apply versioning (/1.x, /next) (#479) * docs: apply versioning (/1.x, /next) * fix: crowdin adds html tags * feat: permanent /2.x url path * fix: navbar item links --- crowdin.yml | 2 + docusaurus.config.js | 31 +- .../current.json | 4 +- .../version-1.x/README.md | 45 + .../version-1.x/admin.md | 13 + .../version-1.x/bugs.md | 28 + .../version-1.x/code-of-conduct.md | 51 ++ .../version-1.x/composer.md | 152 ++++ .../version-1.x/config.md | 35 + .../version-1.x/console.md | 77 ++ .../contributing-docs-translations.md | 26 + .../version-1.x/contributing.md | 170 ++++ .../version-1.x/extend/README.md | 40 + .../version-1.x/extend/admin.md | 214 +++++ .../version-1.x/extend/api-throttling.md | 58 ++ .../version-1.x/extend/api.md | 353 ++++++++ .../version-1.x/extend/assets.md | 7 + .../version-1.x/extend/authorization.md | 206 +++++ .../version-1.x/extend/backend-events.md | 172 ++++ .../version-1.x/extend/cli.md | 15 + .../version-1.x/extend/console.md | 70 ++ .../version-1.x/extend/distribution.md | 40 + .../extend/extending-extensions.md | 122 +++ .../version-1.x/extend/extensibility.md | 65 ++ .../version-1.x/extend/filesystem.md | 129 +++ .../version-1.x/extend/formatting.md | 42 + .../version-1.x/extend/forms.md | 108 +++ .../version-1.x/extend/frontend-pages.md | 218 +++++ .../version-1.x/extend/frontend.md | 422 ++++++++++ .../version-1.x/extend/github-actions.md | 119 +++ .../version-1.x/extend/i18n.md | 467 +++++++++++ .../extend/interactive-components.md | 93 +++ .../version-1.x/extend/language-packs.md | 56 ++ .../version-1.x/extend/mail.md | 59 ++ .../version-1.x/extend/middleware.md | 156 ++++ .../version-1.x/extend/model-visibility.md | 266 ++++++ .../version-1.x/extend/models.md | 334 ++++++++ .../version-1.x/extend/notifications.md | 413 ++++++++++ .../version-1.x/extend/permissions.md | 73 ++ .../version-1.x/extend/post-types.md | 1 + .../version-1.x/extend/routes.md | 281 +++++++ .../version-1.x/extend/search.md | 202 +++++ .../version-1.x/extend/service-provider.md | 65 ++ .../version-1.x/extend/settings.md | 90 ++ .../version-1.x/extend/slugging.md | 1 + .../version-1.x/extend/start.md | 153 ++++ .../extend/static-code-analysis.md | 86 ++ .../version-1.x/extend/testing.md | 565 +++++++++++++ .../version-1.x/extend/theme.md | 27 + .../version-1.x/extend/update-1_0.md | 257 ++++++ .../version-1.x/extend/update-1_x.md | 139 ++++ .../version-1.x/extend/update-b10.md | 53 ++ .../version-1.x/extend/update-b12.md | 34 + .../version-1.x/extend/update-b13.md | 40 + .../version-1.x/extend/update-b14.md | 757 +++++++++++++++++ .../version-1.x/extend/update-b15.md | 60 ++ .../version-1.x/extend/update-b16.md | 138 ++++ .../version-1.x/extend/update-b8.md | 114 +++ .../version-1.x/extend/views.md | 63 ++ .../version-1.x/extenders.md | 23 + .../version-1.x/extensions.md | 118 +++ .../version-1.x/faq.md | 35 + .../version-1.x/install.md | 198 +++++ .../version-1.x/internal/README.md | 7 + .../internal/bundled-extensions-policy.md | 28 + .../version-1.x/internal/extension-manager.md | 87 ++ .../version-1.x/internal/merging-policy.md | 38 + .../version-1.x/internal/merging.md | 29 + .../version-1.x/internal/package-manager.md | 89 ++ .../version-1.x/languages.md | 29 + .../version-1.x/mail.md | 29 + .../version-1.x/releases.md | 15 + .../version-1.x/rest-api.md | 375 +++++++++ .../version-1.x/scheduler.md | 55 ++ .../version-1.x/themes.md | 29 + .../version-1.x/troubleshoot.md | 56 ++ .../version-1.x/update.md | 110 +++ .../current.json | 4 +- .../current.json | 4 +- .../version-1.x/README.md | 45 + .../version-1.x/admin.md | 13 + .../version-1.x/bugs.md | 28 + .../version-1.x/code-of-conduct.md | 51 ++ .../version-1.x/composer.md | 152 ++++ .../version-1.x/config.md | 35 + .../version-1.x/console.md | 77 ++ .../contributing-docs-translations.md | 26 + .../version-1.x/contributing.md | 170 ++++ .../version-1.x/current.json | 42 + .../version-1.x/extend/README.md | 40 + .../version-1.x/extend/admin.md | 217 +++++ .../version-1.x/extend/api-throttling.md | 62 ++ .../version-1.x/extend/api.md | 353 ++++++++ .../version-1.x/extend/assets.md | 7 + .../version-1.x/extend/authorization.md | 235 ++++++ .../version-1.x/extend/backend-events.md | 215 +++++ .../version-1.x/extend/cli.md | 15 + .../version-1.x/extend/console.md | 79 ++ .../version-1.x/extend/data.md | 562 +++++++++++++ .../version-1.x/extend/distribution.md | 40 + .../extend/extending-extensions.md | 122 +++ .../version-1.x/extend/extensibility.md | 65 ++ .../version-1.x/extend/filesystem.md | 129 +++ .../version-1.x/extend/formatting.md | 42 + .../version-1.x/extend/forms.md | 108 +++ .../version-1.x/extend/frontend-pages.md | 215 +++++ .../version-1.x/extend/frontend.md | 418 ++++++++++ .../version-1.x/extend/github-actions.md | 119 +++ .../version-1.x/extend/i18n.md | 467 +++++++++++ .../extend/interactive-components.md | 93 +++ .../version-1.x/extend/language-packs.md | 56 ++ .../version-1.x/extend/mail.md | 59 ++ .../version-1.x/extend/middleware.md | 166 ++++ .../version-1.x/extend/model-visibility.md | 265 ++++++ .../version-1.x/extend/models.md | 334 ++++++++ .../version-1.x/extend/notifications.md | 413 ++++++++++ .../version-1.x/extend/permissions.md | 73 ++ .../version-1.x/extend/post-types.md | 1 + .../version-1.x/extend/routes.md | 281 +++++++ .../version-1.x/extend/search.md | 202 +++++ .../version-1.x/extend/service-provider.md | 65 ++ .../version-1.x/extend/settings.md | 90 ++ .../version-1.x/extend/slugging.md | 1 + .../version-1.x/extend/start.md | 153 ++++ .../extend/static-code-analysis.md | 86 ++ .../version-1.x/extend/testing.md | 565 +++++++++++++ .../version-1.x/extend/theme.md | 27 + .../version-1.x/extend/translate.md | 39 + .../version-1.x/extend/update-1_0.md | 257 ++++++ .../version-1.x/extend/update-1_x.md | 139 ++++ .../version-1.x/extend/update-b10.md | 53 ++ .../version-1.x/extend/update-b12.md | 34 + .../version-1.x/extend/update-b13.md | 40 + .../version-1.x/extend/update-b14.md | 757 +++++++++++++++++ .../version-1.x/extend/update-b15.md | 60 ++ .../version-1.x/extend/update-b16.md | 138 ++++ .../version-1.x/extend/update-b8.md | 114 +++ .../version-1.x/extend/views.md | 63 ++ .../version-1.x/extenders.md | 23 + .../version-1.x/extensions.md | 118 +++ .../version-1.x/faq.md | 35 + .../version-1.x/install.md | 198 +++++ .../version-1.x/internal/README.md | 7 + .../internal/bundled-extensions-policy.md | 28 + .../version-1.x/internal/extension-manager.md | 87 ++ .../version-1.x/internal/merging-policy.md | 38 + .../version-1.x/internal/merging.md | 29 + .../version-1.x/internal/package-manager.md | 89 ++ .../version-1.x/languages.md | 29 + .../version-1.x/mail.md | 29 + .../version-1.x/releases.md | 15 + .../version-1.x/rest-api.md | 375 +++++++++ .../version-1.x/scheduler.md | 55 ++ .../version-1.x/themes.md | 29 + .../version-1.x/troubleshoot.md | 56 ++ .../version-1.x/update.md | 110 +++ .../current.json | 4 +- .../current/README.md | 2 +- .../current/extend/frontend.md | 4 +- .../current/extend/notifications.md | 2 +- .../version-1.x/README.md | 45 + .../version-1.x/admin.md | 13 + .../version-1.x/bugs.md | 28 + .../version-1.x/code-of-conduct.md | 51 ++ .../version-1.x/composer.md | 152 ++++ .../version-1.x/config.md | 35 + .../version-1.x/console.md | 77 ++ .../contributing-docs-translations.md | 26 + .../version-1.x/contributing.md | 170 ++++ .../version-1.x/current.json | 42 + .../version-1.x/extend/README.md | 40 + .../version-1.x/extend/admin.md | 214 +++++ .../version-1.x/extend/api-throttling.md | 58 ++ .../version-1.x/extend/api.md | 353 ++++++++ .../version-1.x/extend/assets.md | 7 + .../version-1.x/extend/authorization.md | 206 +++++ .../version-1.x/extend/backend-events.md | 215 +++++ .../version-1.x/extend/cli.md | 15 + .../version-1.x/extend/console.md | 70 ++ .../version-1.x/extend/data.md | 568 +++++++++++++ .../version-1.x/extend/distribution.md | 40 + .../extend/extending-extensions.md | 122 +++ .../version-1.x/extend/extensibility.md | 65 ++ .../version-1.x/extend/filesystem.md | 129 +++ .../version-1.x/extend/formatting.md | 42 + .../version-1.x/extend/forms.md | 108 +++ .../version-1.x/extend/frontend-pages.md | 226 +++++ .../version-1.x/extend/frontend.md | 502 +++++++++++ .../version-1.x/extend/github-actions.md | 119 +++ .../version-1.x/extend/i18n.md | 475 +++++++++++ .../extend/interactive-components.md | 93 +++ .../version-1.x/extend/language-packs.md | 56 ++ .../version-1.x/extend/mail.md | 59 ++ .../version-1.x/extend/middleware.md | 156 ++++ .../version-1.x/extend/model-visibility.md | 265 ++++++ .../version-1.x/extend/models.md | 334 ++++++++ .../version-1.x/extend/notifications.md | 413 ++++++++++ .../version-1.x/extend/permissions.md | 73 ++ .../version-1.x/extend/post-types.md | 1 + .../version-1.x/extend/routes.md | 281 +++++++ .../version-1.x/extend/search.md | 202 +++++ .../version-1.x/extend/service-provider.md | 65 ++ .../version-1.x/extend/settings.md | 90 ++ .../version-1.x/extend/slugging.md | 1 + .../version-1.x/extend/start.md | 153 ++++ .../extend/static-code-analysis.md | 86 ++ .../version-1.x/extend/testing.md | 565 +++++++++++++ .../version-1.x/extend/theme.md | 27 + .../version-1.x/extend/translate.md | 40 + .../version-1.x/extend/update-1_0.md | 257 ++++++ .../version-1.x/extend/update-1_x.md | 139 ++++ .../version-1.x/extend/update-b10.md | 53 ++ .../version-1.x/extend/update-b12.md | 34 + .../version-1.x/extend/update-b13.md | 40 + .../version-1.x/extend/update-b14.md | 757 +++++++++++++++++ .../version-1.x/extend/update-b15.md | 60 ++ .../version-1.x/extend/update-b16.md | 138 ++++ .../version-1.x/extend/update-b8.md | 114 +++ .../version-1.x/extend/views.md | 63 ++ .../version-1.x/extenders.md | 23 + .../version-1.x/extensions.md | 118 +++ .../version-1.x/faq.md | 35 + .../version-1.x/install.md | 198 +++++ .../version-1.x/internal/README.md | 7 + .../internal/bundled-extensions-policy.md | 28 + .../version-1.x/internal/extension-manager.md | 87 ++ .../version-1.x/internal/merging-policy.md | 38 + .../version-1.x/internal/merging.md | 29 + .../version-1.x/internal/package-manager.md | 89 ++ .../version-1.x/languages.md | 29 + .../version-1.x/mail.md | 29 + .../version-1.x/releases.md | 15 + .../version-1.x/rest-api.md | 375 +++++++++ .../version-1.x/scheduler.md | 55 ++ .../version-1.x/themes.md | 29 + .../version-1.x/troubleshoot.md | 56 ++ .../version-1.x/update.md | 110 +++ .../current.json | 4 +- .../version-1.x/README.md | 45 + .../version-1.x/admin.md | 13 + .../version-1.x/bugs.md | 28 + .../version-1.x/code-of-conduct.md | 51 ++ .../version-1.x/composer.md | 152 ++++ .../version-1.x/config.md | 35 + .../version-1.x/console.md | 77 ++ .../contributing-docs-translations.md | 26 + .../version-1.x/contributing.md | 170 ++++ .../version-1.x/current.json | 42 + .../version-1.x/extend/README.md | 40 + .../version-1.x/extend/admin.md | 214 +++++ .../version-1.x/extend/api-throttling.md | 58 ++ .../version-1.x/extend/api.md | 353 ++++++++ .../version-1.x/extend/assets.md | 7 + .../version-1.x/extend/authorization.md | 206 +++++ .../version-1.x/extend/backend-events.md | 172 ++++ .../version-1.x/extend/cli.md | 15 + .../version-1.x/extend/console.md | 70 ++ .../version-1.x/extend/data.md | 3 + .../version-1.x/extend/distribution.md | 40 + .../extend/extending-extensions.md | 122 +++ .../version-1.x/extend/extensibility.md | 65 ++ .../version-1.x/extend/filesystem.md | 129 +++ .../version-1.x/extend/formatting.md | 42 + .../version-1.x/extend/forms.md | 108 +++ .../version-1.x/extend/frontend-pages.md | 218 +++++ .../version-1.x/extend/frontend.md | 422 ++++++++++ .../version-1.x/extend/github-actions.md | 119 +++ .../version-1.x/extend/i18n.md | 467 +++++++++++ .../extend/interactive-components.md | 93 +++ .../version-1.x/extend/language-packs.md | 56 ++ .../version-1.x/extend/mail.md | 59 ++ .../version-1.x/extend/middleware.md | 156 ++++ .../version-1.x/extend/model-visibility.md | 266 ++++++ .../version-1.x/extend/models.md | 334 ++++++++ .../version-1.x/extend/notifications.md | 413 ++++++++++ .../version-1.x/extend/permissions.md | 73 ++ .../version-1.x/extend/post-types.md | 1 + .../version-1.x/extend/routes.md | 281 +++++++ .../version-1.x/extend/search.md | 202 +++++ .../version-1.x/extend/service-provider.md | 65 ++ .../version-1.x/extend/settings.md | 90 ++ .../version-1.x/extend/slugging.md | 1 + .../version-1.x/extend/start.md | 153 ++++ .../extend/static-code-analysis.md | 86 ++ .../version-1.x/extend/testing.md | 565 +++++++++++++ .../version-1.x/extend/theme.md | 27 + .../version-1.x/extend/translate.md | 3 + .../version-1.x/extend/update-1_0.md | 257 ++++++ .../version-1.x/extend/update-1_x.md | 139 ++++ .../version-1.x/extend/update-b10.md | 53 ++ .../version-1.x/extend/update-b12.md | 34 + .../version-1.x/extend/update-b13.md | 40 + .../version-1.x/extend/update-b14.md | 757 +++++++++++++++++ .../version-1.x/extend/update-b15.md | 60 ++ .../version-1.x/extend/update-b16.md | 138 ++++ .../version-1.x/extend/update-b8.md | 114 +++ .../version-1.x/extend/views.md | 63 ++ .../version-1.x/extenders.md | 23 + .../version-1.x/extensions.md | 118 +++ .../version-1.x/faq.md | 35 + .../version-1.x/install.md | 198 +++++ .../version-1.x/internal/README.md | 7 + .../internal/bundled-extensions-policy.md | 28 + .../version-1.x/internal/extension-manager.md | 87 ++ .../version-1.x/internal/merging-policy.md | 38 + .../version-1.x/internal/merging.md | 29 + .../version-1.x/internal/package-manager.md | 89 ++ .../version-1.x/languages.md | 29 + .../version-1.x/mail.md | 29 + .../version-1.x/releases.md | 15 + .../version-1.x/rest-api.md | 375 +++++++++ .../version-1.x/scheduler.md | 55 ++ .../version-1.x/themes.md | 29 + .../version-1.x/troubleshoot.md | 56 ++ .../version-1.x/update.md | 110 +++ .../current.json | 4 +- .../version-1.x/README.md | 45 + .../version-1.x/admin.md | 13 + .../version-1.x/bugs.md | 28 + .../version-1.x/code-of-conduct.md | 51 ++ .../version-1.x/composer.md | 152 ++++ .../version-1.x/config.md | 35 + .../version-1.x/console.md | 77 ++ .../contributing-docs-translations.md | 26 + .../version-1.x/contributing.md | 170 ++++ .../version-1.x/extend/README.md | 40 + .../version-1.x/extend/admin.md | 214 +++++ .../version-1.x/extend/api-throttling.md | 58 ++ .../version-1.x/extend/api.md | 353 ++++++++ .../version-1.x/extend/assets.md | 7 + .../version-1.x/extend/authorization.md | 206 +++++ .../version-1.x/extend/backend-events.md | 172 ++++ .../version-1.x/extend/cli.md | 15 + .../version-1.x/extend/console.md | 70 ++ .../version-1.x/extend/distribution.md | 40 + .../extend/extending-extensions.md | 122 +++ .../version-1.x/extend/extensibility.md | 65 ++ .../version-1.x/extend/filesystem.md | 129 +++ .../version-1.x/extend/formatting.md | 42 + .../version-1.x/extend/forms.md | 108 +++ .../version-1.x/extend/frontend-pages.md | 218 +++++ .../version-1.x/extend/frontend.md | 422 ++++++++++ .../version-1.x/extend/github-actions.md | 119 +++ .../version-1.x/extend/i18n.md | 467 +++++++++++ .../extend/interactive-components.md | 93 +++ .../version-1.x/extend/language-packs.md | 56 ++ .../version-1.x/extend/mail.md | 59 ++ .../version-1.x/extend/middleware.md | 156 ++++ .../version-1.x/extend/model-visibility.md | 266 ++++++ .../version-1.x/extend/models.md | 334 ++++++++ .../version-1.x/extend/notifications.md | 413 ++++++++++ .../version-1.x/extend/permissions.md | 73 ++ .../version-1.x/extend/post-types.md | 1 + .../version-1.x/extend/routes.md | 281 +++++++ .../version-1.x/extend/search.md | 202 +++++ .../version-1.x/extend/service-provider.md | 65 ++ .../version-1.x/extend/settings.md | 90 ++ .../version-1.x/extend/slugging.md | 1 + .../version-1.x/extend/start.md | 153 ++++ .../extend/static-code-analysis.md | 86 ++ .../version-1.x/extend/testing.md | 565 +++++++++++++ .../version-1.x/extend/theme.md | 27 + .../version-1.x/extend/update-1_0.md | 257 ++++++ .../version-1.x/extend/update-1_x.md | 139 ++++ .../version-1.x/extend/update-b10.md | 53 ++ .../version-1.x/extend/update-b12.md | 34 + .../version-1.x/extend/update-b13.md | 40 + .../version-1.x/extend/update-b14.md | 757 +++++++++++++++++ .../version-1.x/extend/update-b15.md | 60 ++ .../version-1.x/extend/update-b16.md | 138 ++++ .../version-1.x/extend/update-b8.md | 114 +++ .../version-1.x/extend/views.md | 63 ++ .../version-1.x/extenders.md | 23 + .../version-1.x/extensions.md | 118 +++ .../version-1.x/faq.md | 35 + .../version-1.x/install.md | 198 +++++ .../version-1.x/internal/README.md | 7 + .../internal/bundled-extensions-policy.md | 28 + .../version-1.x/internal/extension-manager.md | 87 ++ .../version-1.x/internal/merging-policy.md | 38 + .../version-1.x/internal/merging.md | 29 + .../version-1.x/internal/package-manager.md | 89 ++ .../version-1.x/languages.md | 29 + .../version-1.x/mail.md | 29 + .../version-1.x/releases.md | 15 + .../version-1.x/rest-api.md | 375 +++++++++ .../version-1.x/scheduler.md | 55 ++ .../version-1.x/themes.md | 29 + .../version-1.x/troubleshoot.md | 56 ++ .../version-1.x/update.md | 110 +++ .../current.json | 4 +- .../current/README.md | 2 +- .../current/code-of-conduct.md | 2 +- .../version-1.x/README.md | 45 + .../version-1.x/admin.md | 13 + .../version-1.x/appearance.md | 3 + .../version-1.x/bugs.md | 28 + .../version-1.x/code-of-conduct.md | 51 ++ .../version-1.x/composer.md | 152 ++++ .../version-1.x/config.md | 35 + .../version-1.x/console.md | 77 ++ .../contributing-docs-translations.md | 26 + .../version-1.x/contributing.md | 170 ++++ .../version-1.x/extend/README.md | 40 + .../version-1.x/extend/admin.md | 214 +++++ .../version-1.x/extend/api-throttling.md | 58 ++ .../version-1.x/extend/api.md | 353 ++++++++ .../version-1.x/extend/assets.md | 7 + .../version-1.x/extend/authorization.md | 206 +++++ .../version-1.x/extend/backend-events.md | 172 ++++ .../version-1.x/extend/cli.md | 15 + .../version-1.x/extend/console.md | 77 ++ .../version-1.x/extend/distribution.md | 40 + .../extend/extending-extensions.md | 122 +++ .../version-1.x/extend/extensibility.md | 65 ++ .../version-1.x/extend/filesystem.md | 129 +++ .../version-1.x/extend/formatting.md | 42 + .../version-1.x/extend/forms.md | 108 +++ .../version-1.x/extend/frontend-pages.md | 218 +++++ .../version-1.x/extend/frontend.md | 422 ++++++++++ .../version-1.x/extend/github-actions.md | 119 +++ .../version-1.x/extend/i18n.md | 467 +++++++++++ .../extend/interactive-components.md | 93 +++ .../version-1.x/extend/language-packs.md | 56 ++ .../version-1.x/extend/mail.md | 59 ++ .../version-1.x/extend/middleware.md | 156 ++++ .../version-1.x/extend/model-visibility.md | 266 ++++++ .../version-1.x/extend/models.md | 334 ++++++++ .../version-1.x/extend/notifications.md | 413 ++++++++++ .../version-1.x/extend/permissions.md | 73 ++ .../version-1.x/extend/post-types.md | 1 + .../version-1.x/extend/routes.md | 281 +++++++ .../version-1.x/extend/search.md | 202 +++++ .../version-1.x/extend/service-provider.md | 65 ++ .../version-1.x/extend/settings.md | 90 ++ .../version-1.x/extend/slugging.md | 1 + .../version-1.x/extend/start.md | 153 ++++ .../extend/static-code-analysis.md | 86 ++ .../version-1.x/extend/testing.md | 565 +++++++++++++ .../version-1.x/extend/theme.md | 27 + .../version-1.x/extend/update-1_0.md | 257 ++++++ .../version-1.x/extend/update-1_x.md | 139 ++++ .../version-1.x/extend/update-b10.md | 53 ++ .../version-1.x/extend/update-b12.md | 34 + .../version-1.x/extend/update-b13.md | 40 + .../version-1.x/extend/update-b14.md | 757 +++++++++++++++++ .../version-1.x/extend/update-b15.md | 60 ++ .../version-1.x/extend/update-b16.md | 138 ++++ .../version-1.x/extend/update-b8.md | 114 +++ .../version-1.x/extend/views.md | 63 ++ .../version-1.x/extenders.md | 23 + .../version-1.x/extensions.md | 118 +++ .../version-1.x/faq.md | 35 + .../version-1.x/install.md | 198 +++++ .../version-1.x/internal/README.md | 7 + .../internal/bundled-extensions-policy.md | 28 + .../version-1.x/internal/extension-manager.md | 87 ++ .../version-1.x/internal/merging-policy.md | 38 + .../version-1.x/internal/merging.md | 29 + .../version-1.x/internal/package-manager.md | 89 ++ .../version-1.x/languages.md | 29 + .../version-1.x/mail.md | 29 + .../version-1.x/permissions.md | 3 + .../version-1.x/releases.md | 15 + .../version-1.x/rest-api.md | 375 +++++++++ .../version-1.x/scheduler.md | 55 ++ .../version-1.x/tags.md | 3 + .../version-1.x/themes.md | 29 + .../version-1.x/troubleshoot.md | 56 ++ .../version-1.x/update.md | 110 +++ versioned_docs/version-1.x/README.md | 45 + versioned_docs/version-1.x/admin.md | 15 + versioned_docs/version-1.x/bugs.md | 28 + versioned_docs/version-1.x/code-of-conduct.md | 51 ++ versioned_docs/version-1.x/composer.md | 155 ++++ versioned_docs/version-1.x/config.md | 36 + versioned_docs/version-1.x/console.md | 77 ++ .../contributing-docs-translations.md | 26 + versioned_docs/version-1.x/contributing.md | 171 ++++ versioned_docs/version-1.x/extend/README.md | 40 + versioned_docs/version-1.x/extend/admin.md | 214 +++++ .../version-1.x/extend/api-throttling.md | 61 ++ versioned_docs/version-1.x/extend/api.md | 359 ++++++++ versioned_docs/version-1.x/extend/assets.md | 8 + .../version-1.x/extend/authorization.md | 215 +++++ .../version-1.x/extend/backend-events.md | 174 ++++ versioned_docs/version-1.x/extend/cli.md | 16 + versioned_docs/version-1.x/extend/console.md | 70 ++ .../version-1.x/extend/distribution.md | 41 + .../extend/extending-extensions.md | 125 +++ .../version-1.x/extend/extensibility.md | 68 ++ .../version-1.x/extend/filesystem.md | 132 +++ .../version-1.x/extend/formatting.md | 42 + versioned_docs/version-1.x/extend/forms.md | 114 +++ .../version-1.x/extend/frontend-pages.md | 225 +++++ versioned_docs/version-1.x/extend/frontend.md | 431 ++++++++++ .../version-1.x/extend/github-actions.md | 119 +++ versioned_docs/version-1.x/extend/i18n.md | 474 +++++++++++ .../extend/interactive-components.md | 97 +++ .../version-1.x/extend/language-packs.md | 56 ++ versioned_docs/version-1.x/extend/mail.md | 59 ++ .../version-1.x/extend/middleware.md | 156 ++++ .../version-1.x/extend/model-visibility.md | 271 ++++++ versioned_docs/version-1.x/extend/models.md | 333 ++++++++ .../version-1.x/extend/notifications.md | 417 ++++++++++ .../version-1.x/extend/permissions.md | 74 ++ .../version-1.x/extend/post-types.md | 1 + versioned_docs/version-1.x/extend/routes.md | 282 +++++++ versioned_docs/version-1.x/extend/search.md | 213 +++++ .../version-1.x/extend/service-provider.md | 68 ++ versioned_docs/version-1.x/extend/settings.md | 93 +++ versioned_docs/version-1.x/extend/slugging.md | 1 + versioned_docs/version-1.x/extend/start.md | 153 ++++ .../extend/static-code-analysis.md | 86 ++ versioned_docs/version-1.x/extend/testing.md | 570 +++++++++++++ versioned_docs/version-1.x/extend/theme.md | 28 + .../version-1.x/extend/update-1_0.md | 261 ++++++ .../version-1.x/extend/update-1_x.md | 139 ++++ .../version-1.x/extend/update-b10.md | 53 ++ .../version-1.x/extend/update-b12.md | 35 + .../version-1.x/extend/update-b13.md | 40 + .../version-1.x/extend/update-b14.md | 777 ++++++++++++++++++ .../version-1.x/extend/update-b15.md | 60 ++ .../version-1.x/extend/update-b16.md | 141 ++++ .../version-1.x/extend/update-b8.md | 114 +++ versioned_docs/version-1.x/extend/views.md | 67 ++ versioned_docs/version-1.x/extenders.md | 25 + versioned_docs/version-1.x/extensions.md | 119 +++ versioned_docs/version-1.x/faq.md | 35 + versioned_docs/version-1.x/install.md | 200 +++++ versioned_docs/version-1.x/internal/README.md | 7 + .../internal/bundled-extensions-policy.md | 28 + .../version-1.x/internal/extension-manager.md | 88 ++ .../version-1.x/internal/merging-policy.md | 38 + versioned_docs/version-1.x/languages.md | 30 + versioned_docs/version-1.x/mail.md | 29 + versioned_docs/version-1.x/releases.md | 14 + versioned_docs/version-1.x/rest-api.md | 389 +++++++++ versioned_docs/version-1.x/scheduler.md | 55 ++ versioned_docs/version-1.x/themes.md | 33 + versioned_docs/version-1.x/troubleshoot.md | 57 ++ versioned_docs/version-1.x/update.md | 110 +++ versioned_sidebars/version-1.x-sidebars.json | 155 ++++ versions.json | 3 + 544 files changed, 67565 insertions(+), 25 deletions(-) create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/README.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/admin.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/bugs.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/composer.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/config.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/console.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/contributing.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/README.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/admin.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/api.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/assets.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/cli.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/console.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/extensibility.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/forms.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/github-actions.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/i18n.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/interactive-components.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/language-packs.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/mail.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/middleware.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/model-visibility.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/models.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/notifications.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/permissions.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/post-types.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/routes.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/search.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/settings.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/start.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/testing.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/theme.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/views.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extenders.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/extensions.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/faq.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/install.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/README.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/merging.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/languages.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/mail.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/releases.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/rest-api.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/scheduler.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/themes.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/version-1.x/update.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/README.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/admin.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/bugs.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/composer.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/config.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/console.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/contributing.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/current.json create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/README.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/admin.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/api.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/assets.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/cli.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/console.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/data.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/extensibility.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/forms.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/github-actions.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/i18n.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/interactive-components.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/language-packs.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/mail.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/middleware.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/model-visibility.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/models.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/notifications.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/permissions.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/post-types.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/routes.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/search.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/settings.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/start.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/testing.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/theme.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/translate.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/views.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extenders.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/extensions.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/faq.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/install.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/README.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/merging.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/languages.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/mail.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/releases.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/rest-api.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/scheduler.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/themes.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/version-1.x/update.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/README.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/admin.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/bugs.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/composer.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/config.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/console.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/contributing.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/current.json create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/README.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/admin.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/api.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/assets.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/cli.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/console.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/data.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/extensibility.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/forms.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/github-actions.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/i18n.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/interactive-components.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/language-packs.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/mail.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/middleware.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/model-visibility.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/models.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/notifications.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/permissions.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/post-types.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/routes.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/search.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/settings.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/start.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/testing.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/theme.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/translate.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/views.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extenders.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/extensions.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/faq.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/install.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/README.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/merging.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/languages.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/mail.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/releases.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/rest-api.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/scheduler.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/themes.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md create mode 100644 i18n/it/docusaurus-plugin-content-docs/version-1.x/update.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/README.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/admin.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/bugs.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/composer.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/config.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/console.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/contributing.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/current.json create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/README.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/admin.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/api.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/assets.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/cli.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/console.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/data.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/extensibility.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/forms.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/github-actions.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/i18n.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/interactive-components.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/language-packs.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/mail.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/middleware.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/model-visibility.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/models.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/notifications.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/permissions.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/post-types.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/routes.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/search.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/settings.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/start.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/testing.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/theme.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/translate.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/views.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extenders.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/extensions.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/faq.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/install.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/README.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/merging.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/languages.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/mail.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/releases.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/rest-api.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/scheduler.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/themes.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md create mode 100644 i18n/tr/docusaurus-plugin-content-docs/version-1.x/update.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/README.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/admin.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/bugs.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/composer.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/config.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/console.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/contributing.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/README.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/admin.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/api.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/assets.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/cli.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/console.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/extensibility.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/forms.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/github-actions.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/i18n.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/interactive-components.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/language-packs.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/mail.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/middleware.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/model-visibility.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/models.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/notifications.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/permissions.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/post-types.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/routes.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/search.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/settings.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/start.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/testing.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/theme.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/views.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extenders.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/extensions.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/faq.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/install.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/README.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/merging.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/languages.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/mail.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/releases.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/rest-api.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/scheduler.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/themes.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md create mode 100644 i18n/vi/docusaurus-plugin-content-docs/version-1.x/update.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/README.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/admin.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/appearance.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/bugs.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/composer.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/config.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/console.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/contributing.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/README.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/admin.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/api.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/assets.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/cli.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/console.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/extensibility.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/forms.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/github-actions.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/i18n.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/interactive-components.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/language-packs.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/mail.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/middleware.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/model-visibility.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/models.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/notifications.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/permissions.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/post-types.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/routes.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/search.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/settings.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/start.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/testing.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/theme.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/views.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extenders.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/extensions.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/faq.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/install.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/README.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/merging.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/languages.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/mail.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/permissions.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/releases.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/rest-api.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/scheduler.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/tags.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/themes.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/version-1.x/update.md create mode 100644 versioned_docs/version-1.x/README.md create mode 100644 versioned_docs/version-1.x/admin.md create mode 100644 versioned_docs/version-1.x/bugs.md create mode 100644 versioned_docs/version-1.x/code-of-conduct.md create mode 100644 versioned_docs/version-1.x/composer.md create mode 100644 versioned_docs/version-1.x/config.md create mode 100644 versioned_docs/version-1.x/console.md create mode 100644 versioned_docs/version-1.x/contributing-docs-translations.md create mode 100644 versioned_docs/version-1.x/contributing.md create mode 100644 versioned_docs/version-1.x/extend/README.md create mode 100644 versioned_docs/version-1.x/extend/admin.md create mode 100644 versioned_docs/version-1.x/extend/api-throttling.md create mode 100644 versioned_docs/version-1.x/extend/api.md create mode 100644 versioned_docs/version-1.x/extend/assets.md create mode 100644 versioned_docs/version-1.x/extend/authorization.md create mode 100644 versioned_docs/version-1.x/extend/backend-events.md create mode 100644 versioned_docs/version-1.x/extend/cli.md create mode 100644 versioned_docs/version-1.x/extend/console.md create mode 100644 versioned_docs/version-1.x/extend/distribution.md create mode 100644 versioned_docs/version-1.x/extend/extending-extensions.md create mode 100644 versioned_docs/version-1.x/extend/extensibility.md create mode 100644 versioned_docs/version-1.x/extend/filesystem.md create mode 100644 versioned_docs/version-1.x/extend/formatting.md create mode 100644 versioned_docs/version-1.x/extend/forms.md create mode 100644 versioned_docs/version-1.x/extend/frontend-pages.md create mode 100644 versioned_docs/version-1.x/extend/frontend.md create mode 100644 versioned_docs/version-1.x/extend/github-actions.md create mode 100644 versioned_docs/version-1.x/extend/i18n.md create mode 100644 versioned_docs/version-1.x/extend/interactive-components.md create mode 100644 versioned_docs/version-1.x/extend/language-packs.md create mode 100644 versioned_docs/version-1.x/extend/mail.md create mode 100644 versioned_docs/version-1.x/extend/middleware.md create mode 100644 versioned_docs/version-1.x/extend/model-visibility.md create mode 100644 versioned_docs/version-1.x/extend/models.md create mode 100644 versioned_docs/version-1.x/extend/notifications.md create mode 100644 versioned_docs/version-1.x/extend/permissions.md create mode 100644 versioned_docs/version-1.x/extend/post-types.md create mode 100644 versioned_docs/version-1.x/extend/routes.md create mode 100644 versioned_docs/version-1.x/extend/search.md create mode 100644 versioned_docs/version-1.x/extend/service-provider.md create mode 100644 versioned_docs/version-1.x/extend/settings.md create mode 100644 versioned_docs/version-1.x/extend/slugging.md create mode 100644 versioned_docs/version-1.x/extend/start.md create mode 100644 versioned_docs/version-1.x/extend/static-code-analysis.md create mode 100644 versioned_docs/version-1.x/extend/testing.md create mode 100644 versioned_docs/version-1.x/extend/theme.md create mode 100644 versioned_docs/version-1.x/extend/update-1_0.md create mode 100644 versioned_docs/version-1.x/extend/update-1_x.md create mode 100644 versioned_docs/version-1.x/extend/update-b10.md create mode 100644 versioned_docs/version-1.x/extend/update-b12.md create mode 100644 versioned_docs/version-1.x/extend/update-b13.md create mode 100644 versioned_docs/version-1.x/extend/update-b14.md create mode 100644 versioned_docs/version-1.x/extend/update-b15.md create mode 100644 versioned_docs/version-1.x/extend/update-b16.md create mode 100644 versioned_docs/version-1.x/extend/update-b8.md create mode 100644 versioned_docs/version-1.x/extend/views.md create mode 100644 versioned_docs/version-1.x/extenders.md create mode 100644 versioned_docs/version-1.x/extensions.md create mode 100644 versioned_docs/version-1.x/faq.md create mode 100644 versioned_docs/version-1.x/install.md create mode 100644 versioned_docs/version-1.x/internal/README.md create mode 100644 versioned_docs/version-1.x/internal/bundled-extensions-policy.md create mode 100644 versioned_docs/version-1.x/internal/extension-manager.md create mode 100644 versioned_docs/version-1.x/internal/merging-policy.md create mode 100644 versioned_docs/version-1.x/languages.md create mode 100644 versioned_docs/version-1.x/mail.md create mode 100644 versioned_docs/version-1.x/releases.md create mode 100644 versioned_docs/version-1.x/rest-api.md create mode 100644 versioned_docs/version-1.x/scheduler.md create mode 100644 versioned_docs/version-1.x/themes.md create mode 100644 versioned_docs/version-1.x/troubleshoot.md create mode 100644 versioned_docs/version-1.x/update.md create mode 100644 versioned_sidebars/version-1.x-sidebars.json create mode 100644 versions.json diff --git a/crowdin.yml b/crowdin.yml index 2bfd8dafb..e06eba6da 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -3,3 +3,5 @@ files: translation: /i18n/%two_letters_code%/**/%original_file_name% - source: /docs/**/* translation: /i18n/%two_letters_code%/docusaurus-plugin-content-docs/current/**/%original_file_name% + - source: /versioned_docs/version-1.x/**/* + translation: /i18n/%two_letters_code%/docusaurus-plugin-content-docs/version-1.x/**/%original_file_name% diff --git a/docusaurus.config.js b/docusaurus.config.js index a7d65a479..107f5c3f3 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -52,6 +52,18 @@ const darkCodeTheme = require('prism-react-renderer/themes/dracula'); sidebarPath: require.resolve('./sidebars.js'), sidebarCollapsible: false, editUrl: 'https://github.com/flarum/docs/tree/master', + lastVersion: '1.x', + versions: { + current: { + label: '2.x', + path: '2.x', + }, + '1.x': { + label: '1.x', + path: '/', // backwards compatibility, only needed for 1.x + // banner: 'unmaintained', + }, + }, }, blog: false, theme: { @@ -75,7 +87,8 @@ const darkCodeTheme = require('prism-react-renderer/themes/dracula'); position: 'right', }, { - to: '/', + type: 'doc', + docId: 'README', label: 'Guide', position: 'right', // Anything that isn't `extend`, `'internal`, or contain a slash. @@ -83,13 +96,15 @@ const darkCodeTheme = require('prism-react-renderer/themes/dracula'); activeBaseRegex: '^(\/[a-z][a-z])?\/(?!(extend\/?|internal\/?|)$).*', }, { - to: 'extend', + type: 'doc', + docId: 'extend/README', label: 'Extend', position: 'right', activeBasePath: `extend`, }, { - to: 'internal', + type: 'doc', + docId: 'internal/README', label: 'Internal', position: 'right', activeBasePath: `internal`, @@ -104,7 +119,6 @@ const darkCodeTheme = require('prism-react-renderer/themes/dracula'); label: 'Flarum', position: 'right', items: [ - { href: 'https://flarum.org/', label: 'Home' @@ -118,7 +132,14 @@ const darkCodeTheme = require('prism-react-renderer/themes/dracula'); label: 'GitHub' }, ] - },{ + }, + { + type: 'docsVersionDropdown', + position: 'right', + dropdownItemsAfter: [], + dropdownActiveClassDisabled: true, + }, + { type: 'localeDropdown', position: 'right', }, diff --git a/i18n/de/docusaurus-plugin-content-docs/current.json b/i18n/de/docusaurus-plugin-content-docs/current.json index 1788b0195..a2866fff9 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current.json +++ b/i18n/de/docusaurus-plugin-content-docs/current.json @@ -1,6 +1,6 @@ { "version.label": { - "message": "Weiter", + "message": "2.x", "description": "The label for version current" }, "sidebar.guideSidebar.category.Introduction": { @@ -39,4 +39,4 @@ "message": "Interne Dokumentation", "description": "The label for category Internal Docs in sidebar internalSidebar" } -} \ No newline at end of file +} diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/README.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/README.md new file mode 100644 index 000000000..1fb6df7c7 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/README.md @@ -0,0 +1,45 @@ +- - - +slug: / +- - - + +# Über Flarum + +Flarum ist eine herrlich einfache Diskussionsplattform für deine Website. Es ist schnell, kostenlos und benutzerfreundlich und bietet alle Funktionen, die du für den Betrieb einer erfolgreichen Community benötigst. Zudem ist Flarum äußerst erweiterbar und lässt sich optimal anpassen. + +![Flarum Startseite Screenshot](/en/img/home_screenshot.png) + +## Ziele + +Flarum ist der kombinierte Nachfolger von [esoTalk](https://github.com/esotalk/esoTalk) und [FluxBB](https://fluxbb.org). Flarum ist: + +* **Schnell und einfach.** Kein Durcheinander, kein Ballast, keine komplexen Abhängigkeiten. Flarum wurde mit PHP erstellt, sodass es schnell und einfach bereitgestellt werden kann. Die Oberfläche wird mit [Mithril](https://mithril.js.org) betrieben, einem leistungsstarken JavaScript-Framework mit geringem Platzbedarf. + +* **Schön und responsiv.** Dies ist eine Forensoftware für Menschen. Flarum wurde sorgfältig entwickelt, um plattformübergreifend konsistent und intuitiv zu sein, und zwar sofort nach der Installation. + +* **Leistungsstark und erweiterbar.** Passe Flarum an, erweitere es und integriere es in deine Community. Die Architektur von Flarum ist erstaunlich flexibel, mit einer [leistungsfähigen Erweiterungs-API](/extend/README.md). + +* **Kostenlos und Open Source.** Flarum wird unter der [MIT-Lizenz](https://github.com/flarum/flarum/blob/master/LICENSE) veröffentlicht. + +Mehr über unsere [Philosophie und Werte für Flarum kannst du hier lesen](https://discuss.flarum.org/d/28869-flarum-philosophy-and-values). + +## Unterstütze das Flarum-Projekt + +Flarum ist eine [kostenlose, quelloffene](https://github.com/flarum/core) Software, die von Freiwilligen gepflegt und verwaltet wird. Wir sind auf die Beiträge der Community angewiesen, damit wir Flarum verbessern und erweitern können. + +🧑💻 Wenn du ein Entwickler bist, solltest du in Erwägung ziehen, [zum Kern oder den gebündelten Erweiterungen von Flarum beizutragen](contributing.md). Dies ist **die** effizienteste Art, Flarum zu helfen, und Ihre Arbeit kann viel bewirken: Es gibt Tausende von Flarum-Seiten mit insgesamt Millionen von Endnutzern. + +🧩 Wenn du eine Funktion vermisst oder eine Idee für ein Thema hast, [schreibe eine individuelle Erweiterung](extend/README.md), um Flarum für dich und andere zu verbessern. + +✒️ Wenn du Erfahrung im technischen Schreiben hast, könnten deine Beiträge zu [unserer Dokumentation](https://github.com/flarum/docs/issues) zukünftigen Benutzern, Administratoren und Entwicklern helfen, das Beste aus Flarum zu machen. + +🌐 Wenn du mehrere Sprachen sprichst, könntest du [Übersetzungen](extend/language-packs.md) beisteuern, um Flarum für unzählige Nutzer auf der ganzen Welt zugänglich zu machen. + +💸 Die Flarum Foundation verdient kein Geld mit Flarum, hat aber Rechnungen zu bezahlen. Spenden über [GitHub Sponsors](https://github.com/sponsors/flarum) oder [OpenCollective](https://opencollective.com/flarum) werden immer dankbar angenommen. In der Vergangenheit konnten wir auch einige unserer Hauptentwickler finanziell unterstützen, damit sie in Teilzeit an Flarum arbeiten konnten. Dies wäre ohne eure finanzielle Unterstützung nicht möglich gewesen. + +🧑🤝🧑 Tritt [unserer Community](https://discuss.flarum.org) bei, um über die Entwicklung von Flarum zu sprechen, Hilfe für deine Instanz zu bekommen oder einfach coole Leute zu treffen! Wenn du Erfahrung mit Flarum hast, kannst du auch gerne Anfängern helfen! + +🐛 Wenn ein Fehler existiert, der dich stört, oder eine Idee für eine neue Funktion, die dir durch den Kopf geht, können wir es nicht wissen, wenn du es uns nicht sagst! Wir verfolgen Bugs, Vorschläge und zukünftige Entwicklungspläne [über GitHub](https://github.com/flarum/core/issues). Wenn bereits ein offenes Problem existiert, können Likes und (konstruktive) Zusatzinformationen sehr hilfreich sein! + +📣 Und wenn dir Flarum gefällt, dann erwäge doch darüber zu bloggen/twittern/reden! Mehr Aufmerksamkeit für Flarum führt zu mehr Nutzern, die sich mit Flarum beschäftigen, und damit zu mehr Aktivität, besseren Erweiterungen und einer schnelleren Entwicklung. + +Flarum wäre ohne unsere phänomenale Community nicht möglich. Wenn du daran interessiert bist, einen Beitrag zu leisten, findest du weitere Informationen in den Dokumenten für [Entwicklerbeiträge](contributing.md) und andere [Beiträge](contributing-docs-translations.md). diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/admin.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/admin.md new file mode 100644 index 000000000..c56641a66 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/admin.md @@ -0,0 +1,13 @@ +# Admin-Dashboard + +Das Flarum Admin Dashboard ist eine benutzerfreundliche Oberfläche zur Verwaltung deines Forums. Es ist nur für Benutzer in der Gruppe „Admin“ verfügbar. Um auf das Admin-Dashboard zuzugreifen, klicke oben rechts auf dem Bildschirm auf deinen **Namen** und wähle **Administration** aus. + +Das Admin-Dashboard hat die folgenden Abschnitte: +- **Dashboard** – Zeigt das Haupt-Admin-Dashboard an, das Statistiken und andere relevante Informationen enthält. +- **Basics** - Zeigt die Optionen zum Festlegen grundlegender Forumsdetails wie Name, Beschreibung und Willkommensbanner. +- **E-Mail** - Ermöglicht die Konfiguration von E-Mail-Einstellungen. Siehe [hier](https://docs.flarum.org/mail) für weitere Informationen. +- **Berechtigungen** - Zeigt die Berechtigungen für jede Benutzergruppe an und ermöglicht dir, globale und spezifische Bereiche zu konfigurieren. +- **Erscheinungsbild** - Ermöglicht es, die Farben und das Branding des Forums anzupassen und zusätzliches CSS zur Anpassung hinzuzufügen. +- **Benutzer** – Stellt dir eine paginierte Liste aller Benutzer im Forum zur Verfügung und gibt die Möglichkeit, den Benutzer zu bearbeiten oder administrative Aktionen durchzuführen. + +Abgesehen von den oben genannten Abschnitten ermöglicht das Admin-Dashboard auch die Verwaltung deiner Erweiterungen (einschließlich der Flarum-Core-Erweiterungen wie Tags) im Abschnitt _Features_. Erweiterungen, die das Forum-Thema ändern oder Ihnen erlauben, mehrere Sprachen zu verwenden, werden unter den Abschnitten _Themes_ bzw. _Sprachen_ kategorisiert. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/bugs.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/bugs.md new file mode 100644 index 000000000..df6e7b142 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/bugs.md @@ -0,0 +1,28 @@ +# Fehler melden + +:::danger Sicherheitslücken + +Wenn Du eine Sicherheitslücke in Flarum entdeckst, befolge bitte unsere [Sicherheitsrichtlinie](https://github.com/flarum/core/security/policy), damit wir sie umgehend beheben können. + +::: + +Vielen Dank, dass Du uns beim Testen von Flarum geholfen hast. Wir freuen uns, dich im Team zu haben! Wir brauchen Leute, die *Probleme geduldig lösen* und *sie klar kommunizieren* können. Wie Du wahrscheinlich weißt, erfordert eine gute Fehlerberichterstattung einige Zeit und Mühe. Wenn Du damit einverstanden bist, dann fangen wir an! + +## Duplikate + +Schon einen Fehler gefunden? Wundervoll! Wir würden gerne davon hören — doch zuerst solltest Du dich umsehen, um sicherzustellen, dass Du deine Zeit nicht mit einem bekannten Problem verschwendest: + +- Durchsuche unser [Support-Forum](https://discuss.flarum.org/t/support), um zu sehen, ob es bereits gemeldet wurde. +- Wir könnten an einer Lösung arbeiten, also durchsuche auch unseren [Probleme-Tracker](https://github.com/flarum/core/issues). + +Wenn Du *gründlich* gesucht hast und leer ausgegangen bist, freuen wir uns über deinen Bericht. Wenn es sich nur um ein einfaches Problem handelt (z. B. ein falsch geschriebenes Wort oder ein Grafikfehler), fahre mit dem nächsten Absatz fort. Wenn Du jedoch Fehler siehst oder etwas eindeutig defekt ist, musst Du zuerst einige Informationen sammeln. Bitte gehe zu unserem Leitfaden [Fehlerbehebung](troubleshoot.md) und befolge die dortigen Anweisungen. Sammel so viele Informationen wie möglich! + +## Melden + +Wir verfolgen Probleme auf GitHub. Stelle sicher, dass Du dein Problem im [richtigen Repository](https://github.com/flarum) öffnest und alle Informationen in der Fehlerberichtsvorlage ausfüllst. + +Überprüfe nach Möglichkeit, ob das Problem mit der neuesten Version von Flarum reproduzierbar ist. Wenn Du eine Vorabversion oder eine Entwicklungsversion verwendest, gebe bitte die spezifische Version an, die Du verwendest. + +Bedenke: Das Ziel eines Fehlerberichts ist es, es uns leicht zu machen, den Fehler zu replizieren und zu beheben. Vielleicht möchtest Du [diesen Artikel](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html) lesen, um einige nützliche Tipps zum Schreiben eines effektiven Fehlerberichts zu erhalten. Es ist **erforderlich**, dass Du die notwendigen Schritte zum Reproduzieren des aufgetretenen Problems klar beschreibst. Probleme ohne eindeutige Reproduktionsschritte werden nicht gesichtet. Wenn ein Problem mit der Bezeichnung "Bestätigung erforderlich" länger als 5 Tage keine weiteren Eingaben vom Autor des Problems erhält, wird es geschlossen. + +Sobald Du deinen Bericht gepostet hast, bitten wir dich, *der Diskussion zu folgen* und geduldig zu warten. Möglicherweise müssen wir um weitere Einzelheiten oder Klarstellungen bitten; Doch wir haben immer viel zu tun, und es kann eine Weile dauern, bis wir deinem Bericht die Zeit geben können, die er verdient. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md new file mode 100644 index 000000000..af3197ed1 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md @@ -0,0 +1,51 @@ +# Verhaltenskodex + +### _Willkommen in der Flarum-Community!_ + +... Und danke, dass du dabei bist! Wir sind begeistert von Flarum und freuen uns immer, Menschen zu treffen, denen es genauso geht. Wir möchten, dass *jeder* das Beste aus Flarum und der Flarum-Community herausholt, daher bitten wir Dich, diese Richtlinien zu lesen und zu befolgen. Diese gelten unabhängig davon, ob Du unser Forum, den Discord-Chat, die Kommunikation auf GitHub oder eine andere Form der Kommunikation ohne die Flarum-Community verwendest. + +### Sei vor allem cool! + +Wir sind alle hier, um über Flarum zu sprechen und gemeinsam daran zu arbeiten, es zu einer noch besseren Anwendung zu machen. Ideen zu kritisieren (natürlich durch begründete Argumente) ist ein wichtiger Teil davon. Aber lassen wir uns nicht hinreißen und verfallen in persönliche Angriffe, denn Negativität steht nur im Weg. Wir bitten Dich, Folgendes zu vermeiden: + +- Beleidigende oder beleidigende Sprache sowie jede Art von Hassrede +- Beiträge, die darauf abzielen, andere zu belästigen, sich auszugeben oder zu diffamieren +- Unnötiges Löschen von geposteten Inhalten +- Versuche, die privaten Informationen anderer zu missbrauchen oder offenzulegen +- Obszöne oder sexuell explizite Inhalte +- Spam, Phishing-Posts und alle Aktionen, die darauf abzielen, diese Website zu verunstalten +- Diskussion über Softwarepiraterie und ähnliche Themen + +*Alles oben Genannte sind Gründe für Moderatormaßnahmen.* Wenn Duein Problem mit einem anderen Mitglied habst, bitten wir Dich, dieses nicht selbst zu konfrontieren. Wenn es sich um das Forum handelt, verwende bitte den Befehl *Melden* für den betreffenden Beitrag und überlasse es dann den Mitarbeitern, sich mit der Situation zu befassen. Otherwise, report the violation using our [contact page](https://flarum.org/foundation/contact), option Legal. + +Unsere Moderatoren können Inhalte bearbeiten oder löschen, die anstößig sind oder den Kommunikationsfluss stören. Unsere Moderatoren können Inhalte bearbeiten oder löschen, die anstößig sind oder den Kommunikationsfluss stören. Also, weißt du, *sei cool*. 😎 + +### Verschaffe Dir Gehör + +Möchtest Du eine neue Diskussion beginnen? Lese zuerst unsere [FAQ](faq.md) und folge den Links, um sicherzustellen, dass Du vollständig über das Projekt informiert bist. Dann verbringe einige Zeit damit, das Forum zu durchsuchen, mache Dich mit [dem Tag-System](https://discuss.flarum.org/tags) vertraut und führe ein paar Suchen nach Schlüsselwörtern durch, die mit Deinem Thema zu tun haben: *Es könnte sein, dass jemand bereits eine Diskussion darüber begonnen hat!* + +Wenn Du sicher bist, dass Du bereit bist, eine Diskussion zu beginnen, beachte bitte die folgenden Punkte: + +- Gib ihm einen guten Titel! Die besten Ergebnisse erzielst Du, wenn Dein Titel deutlich macht, worüber Du sprechen möchtest. +- Richtige Tags auswählen. Dies erhöht die Wahrscheinlichkeit, dass dein Beitrag gelesen und zeitnah beantwortet wird. +- *Poste nicht* wiederholt über dasselbe Thema, da dies eher den gegenteiligen Effekt hat. +- If not using a tag set aside for multilingual use, *post in English only.* We can't help you if we don't understand your posts. +- Denken daran, dass du deine Beiträge nicht unterschreiben musst. Wir haben dein Profil, damit wir wissen, wer du bist. + +Bitte bemühen dich, uns bei der Organisation zu helfen. Die Zeit, die wir mit Aufräumen verbringen, ist Zeit, die wir nicht damit verbringen können, dich kennenzulernen, deine Probleme zu besprechen und über Flarum zu sprechen. Und dafür sind wir schließlich alle hier! + +### Lasse deine Antwort zählen + +Du nimmst dir die Zeit, an einer Diskussion teilzunehmen, in der Hoffnung, dass andere deine Ideen lesen und berücksichtigen. Warum sich also nicht die Mühe machen, deine Antwort lesenswert zu machen? + +- Antworte nicht auf einen Titel. Nehmen dir etwas Zeit, um das OP zu *lesen*, und mindestens den Rest des Gesprächs zuerst zu *scannen*. +- Fragen dich, ob deine Antwort zur Diskussion beiträgt. Wenn dies nicht der Fall ist, denke vor dem Posten noch einmal darüber nach. +- Vermeide Ein-Wort-Beiträge, nur um jemandem zuzustimmen; Du kannst dafür den 'Gefällt mir'-Button verwenden. +- Vermeide mehrere Posts hintereinander, wenn einer ausreichen würde. Dies ist ein Forum, kein Chatroom. +- Wenn deine Antwort wahrscheinlich den Verlauf der Diskussion ablenken wird, solltest du stattdessen eine neue Diskussion beginnen. +- Wenn du nur testweise ein bisschen Unsinn posten möchtest, tu dies bitte stattdessen im [Test-Posting](https://discuss.flarum.org/t/sandbox)-Tag. +- Stelle sicher, dass deine Antworten konstruktives Feedback und Unterstützung bieten, um eine integrative Community zu ermöglichen. + +Niemand wird sich über den gelegentlichen Witz oder die kluge Bemerkung beschweren. Wir mögen es, die Stimmung leicht zu halten! Aber auch um die Dinge produktiv zu halten, bitten wir dich, zu vermeiden, dass eine Diskussion insgesamt entgleist. + +> Vielen Dank an Dominion für seine Hilfe bei der Zusammenstellung dieser Richtlinien. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/composer.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/composer.md new file mode 100644 index 000000000..d1178edcb --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/composer.md @@ -0,0 +1,152 @@ + +# Composer + +Flarum uses a program called [Composer](https://getcomposer.org) to manage its dependencies and extensions. You'll need to use composer if you want to: + +- Install or update Flarum through the command line +- Install, update, or remove Flarum extensions through the command line + +This guide is provided as a brief explanation of Composer. We highly recommend consulting the [official documentation](https://getcomposer.org/doc/00-intro.md) for more information. + +:::tip Geteiltes Hosting + +On shared hosting it is recommended to use the Extension Manager extension instead of Composer. It is a graphical interface for Composer that allows you to install, update and remove extensions without the need for SSH access. You can directly install Flarum using an archive file, without the need for Composer. With the extension manager pre-installed, check the [installation guide](install.md#installing-by-unpacking-an-archive) for more information. + +::: + +## What is Composer? + +> Composer is a tool for dependency management in PHP. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you. — [Composer Introduction](https://getcomposer.org/doc/00-intro.md](https://getcomposer.org/doc/00-intro.md)) + +Each Flarum installation consists primarily of Flarum core and a set of [extensions](extensions.md). Each of these has its own dependencies and releases. + +Back in the day, forum frameworks would manage extensions by having users upload zip files with the extension code. That seems simple enough, but issues quickly become evident: + +- Uploading random zip files from the internet tends to be a bad idea. Requiring that extensions be downloaded from a central source like [Packagist](https://packagist.org/) makes it somewhat more tedious to spam malicious code, and ensures that source code is available on GitHub for free/public extensions. +- Let's say Extension A requires v4 of some library, and Extension B requires v5 of that same library. With a zip-based solution, either one of the two dependencies could override the other, causing all sorts of inconsistent problems. Or both would attempt to run at once, which would cause PHP to crash (you can't declare the same class twice). +- Zip files can cause a lot of headache if trying to automate deployments, run automated tests, or scale to multiple server nodes. +- There is no good way to ensure conflicting extension versions can't be installed, or that system PHP version and extension requirements are met. +- Sure, we can upgrade extensions by replacing the zip file. But what about upgrading Flarum core? And how can we ensure that extensions can declare which versions of core they're compatible with? + +Composer takes care of all these issues, and more! + +## Flarum and Composer + +When you go to [install Flarum](install.md#installing), you're actually doing 2 things: + +1. Downloading a boilerplate "skeleton" for Flarum. This includes an `index.php` file that handles web requests, a `flarum` file that provides a CLI, and a bunch of web server config and folder setup. This is taken from the [`flarum/flarum` github repository](https://github.com/flarum/flarum), and doesn't actually contain any of the code necessary for Flarum to run. +2. Installing `composer` packages necessary for Flarum, namely Flarum core, and several bundled extensions. These are called by the `index.php` and `flarum` files from step 1, and are the implementation of Flarum. These are specified in a `composer.json` file included in the skeleton. + +When you want to update Flarum or add/update/remove extensions, you'll do so by running `composer` commands. Each command is different, but all commands follow the same general process: + +1. Update the `composer.json` file to add/remove/update the package. +2. Do a bunch of math to get the latest compatible versions of everything if possible, or figure out why the requested arrangement is impossible. +3. If everything works, download new versions of everything that needs to be updated. If not, revert the `composer.json` changes + +When running `composer.json` commands, make sure to pay attention to the output. If there's an error, it'll probably tell you if it's because of extension incompatibilities, an unsupported PHP version, missing PHP extensions, or something else. + +### The `composer.json` File + +As mentioned above, the entire composer configuration for your Flarum site is contained inside the `composer.json` file. You can consult the [composer documentation](https://getcomposer.org/doc/04-schema.md) for a specific schema, but for now, let's go over an annotated `composer.json` from `flarum/flarum`: + +```json +{ + // This following section is mostly just metadata about the package. + // For forum admins, this doesn't really matter. + "name": "flarum/flarum", + "description": "Delightfully simple forum software.", + "type": "project", + "keywords": [ + "forum", + "discussion" + ], + "homepage": "https://flarum.org/", + "license": "MIT", + "authors": [ + { + "name": "Flarum", + "email": "info@flarum.org", + "homepage": "https://flarum.org/team" + } + ], + "support": { + "issues": "https://github.com/flarum/core/issues", + "source": "https://github.com/flarum/flarum", + "docs": "https://flarum.org/docs/" + }, + // End of metadata + + // This next section is the one we care about the most. + // It's a list of packages we want, and the versions for each. + // We'll discuss this shortly. + "require": { + "flarum/core": "^1.0", + "flarum/approval": "*", + "flarum/bbcode": "*", + "flarum/emoji": "*", + "flarum/lang-english": "*", + "flarum/flags": "*", + "flarum/likes": "*", + "flarum/lock": "*", + "flarum/markdown": "*", + "flarum/mentions": "*", + "flarum/nicknames": "*", + "flarum/pusher": "*", + "flarum/statistics": "*", + "flarum/sticky": "*", + "flarum/subscriptions": "*", + "flarum/suspend": "*", + "flarum/tags": "*" + }, + + // Various composer config. The ones here are sensible defaults. + // See https://getcomposer.org/doc/06-config.md for a list of options. + "config": { + "preferred-install": "dist", + "sort-packages": true + }, + + // If composer can find a stable (not dev, alpha, or beta) version + // of a package, it should use that. Generally speaking, production + // sites shouldn't run beta software unless you know what you're doing. + "prefer-stable": true +} +``` + +Let's focus on that `require` section. Each entry is the name of a composer package, and a version string. To read more about version strings, see the relevant [composer documentation](https://semver.org/). + +For Flarum projects, there's several types of entries you'll see in the `require` section of your root install's `flarum/core`: + +- You MUST have a `flarum/core` entry. This should have an explicit version string corresponding to the major release you want to install. For Flarum 1.x versions, this would be `^1.0`. +- You should have an entry for each extension you've installed. Some bundled extensions are included by default (e.g. `flarum/tags`, `flarum/suspend`, etc), [others you'll add via composer commands](extensions.md). Unless you have a reason to do otherwise (e.g. you're testing a beta version of a package), we recommend using an asterisk as the version string for extensions (`*`). This means "install the latest version compatible with my flarum/core". +- Some extensions / features might require PHP packages that aren't Flarum extensions. For example, you need the guzzle library to use the [Mailgun mail driver](mail.md). In these cases, the instructions for the extension/feature in question should explain which version string to use. + +## How to install Composer? + +As with any other software, Composer must first be [installed](https://getcomposer.org/download/) on the server where Flarum is running. There are several options depending on the type of web hosting you have. + +### Dedicated Web Server + +In this case you can install composer as recommended in the Composer [guide](https://getcomposer.org/doc/00-intro.md#system-requirements) + +### Managed / Shared hosting + +If Composer is not preinstalled (you can check this by running `composer --version`), you can use a [manual installation](https://getcomposer.org/composer-stable.phar). Just upload the composer.phar to your folder and run `/path/to/your/php7 composer.phar COMMAND` for any command documented as `composer COMMAND`. + +:::danger + +Some articles on the internet will mention that you can use tools like a PHP shell. If you are not sure what you are doing or what they are talking about - be careful! An unprotected web shell is **extremely** dangerous. + +::: + +## How do I use Composer? + +You'll need to use Composer over the **C**ommand-**l**ine **i**nterface (CLI). Be sure you can access your server over **S**ecure **Sh**ell (SSH). + +Once you have Composer installed, you should be able to run Composer commands in your SSH terminal via `composer COMMAND`. + +:::info Optimierungen + +After most commands, you'll want to run `composer dump-autoload -a`. Essentially, this caches PHP files so they run faster. + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/config.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/config.md new file mode 100644 index 000000000..9dd3cedda --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/config.md @@ -0,0 +1,35 @@ +# Konfigurationsdatei + +Es existiert nur ein Ort, an dem die Flarum-Konfiguration nicht über das Flarum-Admin-Dashboard (mit Ausnahme der Datenbank) geändert werden kann, und das ist die Datei `config.php`, die sich im Stammverzeichnis deiner Flarum-Installation befindet. + +Diese Datei ist zwar klein, enthält aber Details, die für das Funktionieren deiner Flarum-Installation entscheidend sind. + +Wenn die Datei existiert, teilt es Flarum mit, dass es bereits installiert wurde. Es versorgt Flarum auch mit Datenbankinformationen und mehr. + +Hier ist ein kurzer Überblick darüber, was alles mit einer Beispieldatei bedeutet: + +```php + false, // aktiviert oder deaktiviert den Debug-Modus, der zum Beheben von Problemen verwendet wird + 'offline' => false, // aktiviert oder deaktiviert den Site-Wartungsmodus. Dadurch wird deine Website für alle Benutzer (einschließlich Administratoren) unzugänglich. + 'database' => + array ( + 'driver' => 'mysql', // der Datenbanktreiber, d.h. MySQL, MariaDB... + 'host' => 'localhost', // der Host der Verbindung, in den meisten Fällen localhost, es sei denn, es wird ein externer Dienst verwendet + 'database' => 'flarum', // der Name der Datenbank in der Instanz + 'username' => 'root', // Datenbank-Benutzername + 'password' => '', // Datenbank Passwort + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', // das Präfix für die Tabellen, nützlich, wenn du dieselbe Datenbank mit einem anderen Dienst teilst + 'port' => '3306', // der Port der Verbindung, standardmäßig 3306 bei MySQL + 'strict' => false, + ), + 'url' => 'https://flarum.localhost', // die URL-Installation, du solltest dies ändern, wenn du die Domain wechselst + 'paths' => + array ( + 'api' => 'api', // /api geht zur API + 'admin' => 'admin', // /admin geht zum Admin + ), +); +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/console.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/console.md new file mode 100644 index 000000000..b7dc5d7bf --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/console.md @@ -0,0 +1,77 @@ +# Konsole + +Zusätzlich zum Admin-Dashboard bietet Flarum mehrere Konsolenbefehle, mit denen du dein Forum über das Terminal verwalten kannst. + +Using the console: + +1. `ssh` in den Server, auf dem deine Flarum-Installation gehostet wird +2. `cd` to the folder that contains the file `flarum` +3. Befehl über `php flarum [command]` ausführen + +## Standardbefehle + +### list + +Listet alle verfügbaren Verwaltungsbefehle sowie Anweisungen zur Verwendung von Verwaltungsbefehlen auf + +### help + +`php flarum help [command_name]` + +Zeigt die Hilfeausgabe für einen bestimmten Befehl an. + +Du kannst die Hilfe auch in anderen Formaten ausgeben, indem du die Option --format verwendest: + +`php flarum help --format=xml list` + +Um die Liste der verfügbaren Befehle anzuzeigen, verwende bitte den list-Befehl. + +### info + +`php flarum info` + +Get information about Flarum's core and installed extensions. Dies ist sehr nützlich zum Debuggen von Problemen und sollte bei Supportanfragen mitgeteilt werden. + +### cache:clear + +`php flarum cache:clear` + +Löscht den Flarum-Cache des Backends, einschließlich generierter js/css, Textformatierer-Cache und zwischengespeicherter Übersetzungen. Dies sollte nach dem Installieren oder Entfernen von Erweiterungen ausgeführt werden, und das Ausführen sollte der erste Schritt sein, wenn Probleme auftreten. + +### assets:publish + +`php flarum assets:publish` + +Assets aus Kern und Erweiterungen veröffentlichen (z. B. kompiliertes JS/CSS, Bootstrap-Symbole, Logos usw.). Dies ist nützlich, wenn deine Assets beschädigt wurden oder wenn du [filesystem drivers](extend/filesystem.md) für die `flarum-assets`-Festplatte ausgetauscht hast. + +### migrate + +`php flarum migrate` + +Führt alle ausstehenden Migrationen aus. Dies sollte verwendet werden, wenn eine Erweiterung hinzugefügt oder aktualisiert wird, die die Datenbank ändert. + +### migrate:reset + +`php flarum migrate:reset --extension [extension_id]` + +Alle Migrationen für eine Erweiterung zurücksetzen. Dies wird hauptsächlich von Erweiterungsentwicklern verwendet, doch gelegentlich musst du dies möglicherweise ausführen, wenn du eine Erweiterung entfernst und alle deine Daten aus der Datenbank löschen möchtest. Bitte beachte, dass die betreffende Erweiterung derzeit installiert (jedoch nicht unbedingt aktiviert) sein muss, damit dies funktioniert. + +### schedule:run + +`php flarum schedule:run` + +Viele Erweiterungen verwenden geplante Jobs, um Aufgaben in regelmäßigen Abständen auszuführen. Dies kann Datenbankbereinigungen, das Posten geplanter Entwürfe, das Erstellen von Sitemaps usw. umfassen. Wenn eine deiner Erweiterungen geplante Jobs verwendet, solltest du einen [Cron-Job](https://ostechnix.com/a-beginners-guide-to-cron-jobs/) hinzufügen, um diesen Befehl in regelmäßigen Abständen auszuführen: + +``` +* * * * * cd /path-to-your-flarum-install && php flarum schedule:run >> /dev/null 2>&1 +``` + +Dieser Befehl sollte im Allgemeinen nicht manuell ausgeführt werden. + +Beachte, dass einige Hosts es dir nicht erlauben, die Cron-Konfiguration direkt zu bearbeiten. In diesem Fall solltest du dich an deinen Host wenden, um weitere Informationen zum Planen von Cron-Jobs zu erhalten. + +### schedule:list + +`php flarum schedule:list` + +Dieser Befehl gibt eine Liste geplanter Befehle zurück (weitere Informationen findest du unter `schedule:run`). Dies ist nützlich, um zu bestätigen, dass die von deinen Erweiterungen bereitgestellten Befehle ordnungsgemäß registriert sind. Dies **kann nicht** überprüfen, ob Cron-Jobs erfolgreich geplant wurden oder ausgeführt werden. \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md new file mode 100644 index 000000000..9b81efc48 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md @@ -0,0 +1,26 @@ +# Dokumente und Übersetzung + +## Dokumentation hinzufügen + +Das Hinzufügen von Dokumentation kann unzähligen zukünftigen Flarum-Benutzern helfen. Ein paar Ideen, woran man arbeiten könnte: + +- Benutzerhandbücher, um Flarum-Endbenutzern mit einigen erweiterten Flarum-Funktionen zu helfen. +- Mehr [häufig gestellte Fragen](faq.md). +- Erweiterte [Fehlerbehebung](troubleshoot.md)s Schritte. +- Schritt-für-Schritt-Tutorials für die Entwicklung oder Installation von Flarum. +- [Technische Referenzhandbücher](extend/README.md) für Entwickler von Erweiterungen. +- Wir verbessern buchstäblich alles andere, von dem Du glaubst, dass wir es näher erläutern oder besser erklären sollten. + +Eine gute Möglichkeit, Themen zu finden, über die Sie schreiben können, besteht darin, im [Support-Tag](https://discuss.flarum.org/t/support) unserer Community nach häufig gestellten Fragen zu suchen. + +## Flarum übersetzen + +Wir möchten, dass Flarum für alle zugänglich ist, unabhängig von der Sprache! Indem Du Übersetzungen beisteuerst, tust Du es viel mehr Menschen möglich, Flarum zu genießen. Das Beste ist, dass wir benutzerfreundliche GUIs für Übersetzungen verwenden, sodass keine technischen Kenntnisse erforderlich sind, um zu helfen! + +Übersetzungen für Flarum Core, gebündelte Erweiterungen und Community-Erweiterungen werden über [Weblate](https://weblate.rob006.net/projects/flarum/) verwaltet. + +Übersetzungen für diese Dokumentation werden über [Crowdin](https://crowdin.com/project/flarum-docs) verwaltet. + +Die Flarum Foundation hat die Organisation "flarum-lang" gegründet, um Übersetzer zu unterstützen und die kontinuierliche Verfügbarkeit von Sprachpaketen sicherzustellen. Du kannst mehr darüber erfahren, indem Du das [GitHub-Repository](https://github.com/flarum-lang/about) besuchst. + +Wenn Du ein vorhandenes Sprachpaket unterstützen, eine neue Übersetzung starten möchtest oder bei der Verwendung von Weblate oder Crowdin auf Probleme stößt, [wende dich am besten an das `flarum-lang`-Team](https://discuss.flarum.org/d/27519-the-flarum-language-project). diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/contributing.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/contributing.md new file mode 100644 index 000000000..2c870c07e --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/contributing.md @@ -0,0 +1,170 @@ +# Hilf Flarum aufzubauen + +Interested in contributing to Flarum development? That's great! From [opening a bug report](bugs.md) to creating a pull request: every single one is appreciated and welcome. Flarum wouldn't be possible without our community contributions. + +Before contributing, please read the [code of conduct](code-of-conduct.md). + +This document is a guide for developers who want to contribute code to Flarum. If you're just getting started, we recommend that you read the [Getting Started](/extend/start.md) documentation in the Extension docs to understand a bit more about how Flarum works. + +## Why Contribute to Flarum? + +⚡ **Have Real Impact.** There are thousands of Flarum instances, with millions of aggregate end users. By contributing to Flarum, your code will have a positive impact on all of them. + +🔮 **Shape the Future of Flarum.** We have a long backlog, and limited time. If you're willing to champion a feature or change, it's much more likely to happen, and you'll be able to enact your vision for it. Plus, our roadmap and milestones are set by our [core development team](https://flarum.org/team), and all of us started as contributors. The best road to influence is contributing. + +🧑‍💻 **Become a Better Engineer.** Our codebase is modern, and we heavily value good engineering and clean code. There's also a lot of interesting, challenging problems to solve regarding design, infrastructure, performance, and extensibility. Especially if you're a student or early in your career, working on Flarum is a great opportunity to build development skills. + +🎠 **It's Fun!** We really enjoy working on Flarum: there's a lot of interesting challenges and fun features to build. We also have an active community on [our forums](https://discuss.flarum.org) and [Discord server](https://flarum.org/chat). + +## What to Work On + +Check out our upcoming [Milestones](https://github.com/flarum/core/milestones) for an overview of what needs to be done. See the [Good first issue](https://github.com/flarum/core/labels/Good%20first%20issue) label for a list of issues that should be relatively easy to get started with. If there's anything you're unsure of, don't hesitate to ask! All of us were just starting out once. + +If you're planning to go ahead and work on something, please comment on the relevant issue or create a new one first. This way we can ensure that your precious work is not in vain. + +Since Flarum is so extension-driven, we highly recommend [our extension docs](extend/README.md) as a reference when working on core, as well as for bundled extensions. You should start with [the introduction](extend/README.md) for a better understanding of our extension philosophy. + +## Development Setup + +### Setting Up a Local Codebase + +[flarum/flarum](https://github.com/flarum/flarum) is a "skeleton" application which uses Composer to download the core package and a bunch of extensions. Source code for Flarum core, extensions, and all packages used by the aforementioned is located in the Flarum monorepo [flarum/framework](https://github.com/flarum/framework). In order to contribute to these, you'll need to fork and clone the monorepo repository locally, and then add it to your dev environment as a [Composer path repository](https://getcomposer.org/doc/05-repositories.md#path): + +```bash +git clone https://github.com/flarum/flarum.git +cd flarum + +# Or, when you want to clone directly into the current directory +git clone https://github.com/flarum/flarum.git . +# Note, the directory must be empty + +# Set up a Composer path repository for Flarum monorepo packages +composer config repositories.0 path "PATH_TO_MONOREPO/*/*" +git clone https://github.com//framework.git PATH_TO_MONOREPO +``` + +Next, ensure that Composer accepts unstable releases from your local copies by setting the `minimum-stability` key to `dev` in `composer.json`. + +Finally, run `composer install` to complete the installation from the path repositories. + +After your local installation is set up, make sure you've enabled `debug` mode in **config.php**, and set `display_errors` to `On` in your php config. This will allow you to see error details for both Flarum and PHP. Debug mode also forces a re-compilation of Flarum's asset files on each request, removing the need to call `php flarum cache:clear` after each change to the extension's JavaScript or CSS. + +Flarum's front-end code is written in ES6 and transpiled into JavaScript. During development you will need to recompile the JavaScript using [Node.js](https://nodejs.org/) and [`yarn`](https://yarnpkg.com/). **Please do not commit the resulting `dist` files when sending PRs**; this is automatically taken care of when changes are merged into the `main` branch. + +To contribute to the frontend, first install the JavaScript dependencies. The monorepo uses [yarn workspaces](https://classic.yarnpkg.com/lang/en/docs/workspaces/) to easily install JS dependencies across all packages within. + +```bash +cd packages/framework +yarn install +``` + +Then you can watch JavaScript files for changes during development: + +```bash +cd framework/core/js +yarn dev +``` + +The process is the same for extensions. + +```bash +cd extensions/tags/js +yarn dev +``` + +### Development Tools + +After you've forked and cloned the repositories you'll be working on, you'll need to set up local hosting so you can test out your changes. Flarum doesn't currently come with a development server, so you'll need to set up Apache/NGINX/Caddy/etc to serve this local Flarum installation. + +Alternatively, you can use tools like, [Laravel Valet](https://laravel.com/docs/master/valet) (Mac), [XAMPP](https://www.apachefriends.org/index.html) (Windows), or [Docker-Flarum](https://github.com/mondediefr/docker-flarum) (Linux) to serve a local forum. + +Most Flarum contributors develop with [PHPStorm](https://www.jetbrains.com/phpstorm/download/) or [Visual Studio Code](https://code.visualstudio.com/). + +## Development Workflow + +A typical contribution workflow looks like this: + +0. 🧭 **Plan** out your contribution + * Figure out [which issue you want to tackle](#what-to-work-on) + * Set up a [development environment](#setting-up-a-local-codebase) + +1. 🌳 **Branch** off the appropriate branch into a new feature branch. + * *Bug fixes* should be sent to the latest stable branch. + * *Minor* features that are fully backwards compatible with the current Flarum release may be sent to the latest stable branch. + * *Major* features should always be sent to the `main` branch, which contains the upcoming Flarum release. + * Internally we use the naming scheme `/` (eg. `tz/refactor-frontend`). + +2. 🔨 **Write** some code. + * See below about [Coding Style](#coding-style). + +3. 🚦 **Test** your code. + * Add unit tests as necessary when fixing bugs or adding features. + * Run the test suite with `vendor/bin/phpunit` in the relevant package folder. + * See [here](extend/testing.md) for more information about testing in Flarum. + +4. 💾 **Commit** your code with a descriptive message. + * If your change resolves an existing issue (usually, it should) include "Fixes #123" on a newline, where 123 is the issue number. + * Follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) specification. + * *Fix* commits should describe the issue fixed, not how it was fixed. + +5. 🎁 **Submit** a Pull Request on GitHub. + * Fill out the pull request template. + * If your change is visual, include a screenshot or GIF demonstrating the change. + * Do NOT check-in the JavaScript `dist` files. These will be compiled automatically on merge. + +6. 🤝 **Engage** with the Flarum team for approval. + * Team members will review your code. We may suggest some changes or improvements or alternatives, but for small changes your pull request should be accepted quickly. + * When addressing feedback, push additional commits instead of overwriting or squashing (we will squash on merge). + +7. 🕺 **Dance** like you just contributed to Flarum. + +## Coding Style + +In order to keep the Flarum codebase clean and consistent, we have a number of coding style guidelines that we follow. When in doubt, read the source code. + +Don't worry if your code styling isn't perfect! StyleCI and Prettier will automatically check formatting for every pull request. This allows us to focus on the content of the contribution, not the code style. + +### PHP + +Flarum follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) coding standard and the [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) autoloading standard. On top of this, we conform to a number of [other style rules](https://github.com/flarum/framework/blob/main/.styleci.yml). We use PHP 7 type hinting and return type declarations where possible, and [PHPDoc](https://docs.phpdoc.org/) to provide inline documentation. Try and mimic the style used by the rest of the codebase in your contributions. + +* Namespaces should be singular (eg. `Flarum\Discussion`, not `Flarum\Discussions`) +* Interfaces should be suffixed with `Interface` (eg. `MailableInterface`) +* Abstract classes should be prefixed with `Abstract` (eg. `AbstractModel`) +* Traits should be suffixed with `Trait` (eg. `ScopeVisibilityTrait`) + +### JavaScript + +Flarum's JavaScript mostly follows the [Airbnb Style Guide](https://github.com/airbnb/javascript). We use [ESDoc](https://esdoc.org/manual/tags.html) to provide inline documentation. + +### Database + +**Columns** should be named according to their data type: +* DATETIME or TIMESTAMP: `{verbed}_at` (eg. created_at, read_at) or `{verbed}_until` (eg. suspended_until) +* INT that is a count: `{noun}_count` (eg. comment_count, word_count) +* Foreign key: `{verbed}_{entity}_id` (eg. hidden_user_id) + * Verb can be omitted for primary relationship (eg. post author is just `user_id`) +* BOOL: `is_{adjective}` (eg. is_locked) + +**Tables** should be named as follows: +* Use plural form (`discussions`) +* Separate multiple words with underscores (`access_tokens`) +* For relationships tables, join the two table names in singular form with an underscore in alphabetical order (eg. `discussion_user`) + +### CSS + +Flarum's CSS classes roughly follow the [SUIT CSS naming conventions](https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md) using the format `.ComponentName-descendentName--modifierName`. + +### Übersetzungen + +We use a [standard key format](/extend/i18n.md#appendix-a-standard-key-format) to name translation keys descriptively and consistently. + +## Contributor License Agreement + +By contributing your code to Flarum you grant the Flarum Foundation (Stichting Flarum) a non-exclusive, irrevocable, worldwide, royalty-free, sublicensable, transferable license under all of Your relevant intellectual property rights (including copyright, patent, and any other rights), to use, copy, prepare derivative works of, distribute and publicly perform and display the Contributions on any licensing terms, including without limitation: (a) open source licenses like the MIT license; and (b) binary, proprietary, or commercial licenses. Except for the licenses granted herein, You reserve all right, title, and interest in and to the Contribution. + +You confirm that you are able to grant us these rights. You represent that You are legally entitled to grant the above license. If Your employer has rights to intellectual property that You create, You represent that You have received permission to make the Contributions on behalf of that employer, or that Your employer has waived such rights for the Contributions. + +You represent that the Contributions are Your original works of authorship, and to Your knowledge, no other person claims, or has the right to claim, any right in any invention or patent related to the Contributions. You also represent that You are not legally obligated, whether by entering into an agreement or otherwise, in any way that conflicts with the terms of this license. + +The Flarum Foundation acknowledges that, except as explicitly described in this Agreement, any Contribution which you provide is on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/README.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/README.md new file mode 100644 index 000000000..1f10bb747 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/README.md @@ -0,0 +1,40 @@ +- - - +slug: '/extend' +- - - + +# Extending Flarum + +Flarum ist minimalistisch, aber auch sehr erweiterbar. Tatsächlich sind die meisten Funktionen, die mit Flarum geliefert werden, tatsächlich Erweiterungen! + +This approach makes Flarum extremely customizable. A user can disable any features they don't use on their forum, and install other extensions to make a forum perfect for their community. + +In order to achieve this extensibility, Flarum has been built with rich APIs and extension points. With some programming knowledge, you can leverage these APIs to add just about any feature you want. This section of the documentation aims to teach you how Flarum works, and how to use the APIs so that you can build your own extensions. + +## Core vs. Extensions + +Where do we draw the line between Flarum's core and its extensions? Why are some features included in the core, and others aren't? It is important to understand this distinction so that we can maintain consistency and quality within Flarum's ecosystem. + +**Flarum's core** is not intended to be packed full of features. Rather, it is a scaffold, or a framework, which provides a reliable foundation on which extensions can build. It contains only basic, unopinionated functionality that is essential to a forum: discussions, posts, users, groups, and notifications. + +**Bundled extensions** are features that are packaged with Flarum and enabled by default. They are extensions just like any other, and may be disabled and uninstalled. While their scope is not intended to address all use-cases, the idea is to make them generic and configurable enough that they can satisfy the majority. + +**Third-party extensions** are features which are made by others and are not officially supported by the Flarum team. They can be built and used to address more specific use-cases. + +If you are aiming to address a bug or shortcoming of the core, or of an existing bundled extension, it may be appropriate to *contribute to the respective project* rather than disperse effort on a new third-party extension. It is a good idea to start a discussion on the [Flarum Community](https://discuss.flarum.org/) to get the perspective of the Flarum developers. + +## Useful Resources + +- [This Documentation](start.md) +- [Tips for Beginning Developers](https://discuss.flarum.org/d/5512-extension-development-tips) +- [Flarum CLI](https://github.com/flarum/cli) +- [Developers explaining their workflow for extension development](https://discuss.flarum.org/d/6320-extension-developers-show-us-your-workflow) +- [Extension namespace tips](https://discuss.flarum.org/d/9625-flarum-extension-namespacing-tips) +- [Mithril js documentation](https://mithril.js.org/) +- [Laravel API Docs](https://laravel.com/api/8.x/) +- [Flarum API Docs](https://api.flarum.org) +- [ES6 cheatsheet](https://github.com/DrkSephy/es6-cheatsheet) + +### Getting help + +- [Official Flarum Dev Community](https://discuss.flarum.org/t/dev) +- [Join us on #extend in our discord chat](https://flarum.org/discord/) diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/admin.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/admin.md new file mode 100644 index 000000000..fba49cd30 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/admin.md @@ -0,0 +1,214 @@ +# Admin-Dashboard + +Beta 15 führte ein komplett neu gestaltetes Admin-Panel und eine Frontend-API ein. Es ist jetzt einfacher denn je, deiner Erweiterung Einstellungen oder Berechtigungen hinzuzufügen. + +Before beta 15, extension settings were either added in a `SettingsModal` or they added a new page for more complex settings. Now, every extension has a page containing info, settings, and the extension's own permissions. + +You can simply register settings, extend the base [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage), or provide your own completely custom page. + +## Erweiterungsdaten-API + +This new API allows you to add settings to your extension with very few lines of code. + +### Informiere die API über Deine Erweiterung + +Before you can register anything, you need to tell `ExtensionData` what extension it is about to get data for. + +Simply run the `for` function on `app.extensionData` passing in the id of your extension. To find you extension id, take the composer name and replace any slashes with dashes (example: 'fof/merge-discussions' becomes 'fof-merge-discussions'). Extensions with the `flarum-` and `flarum-ext-` will omit those from the name (example: 'webbinaro/flarum-calendar' becomes 'webbinaro-calendar'). + +For the following example, we will use the fictitious extension 'acme/interstellar': + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') +}); +``` + +Once that is done, you can begin adding settings and permissions. + +:::tip Hinweis + +All registration functions on `ExtensionData` are chainable, meaning you can call them one after another without running `for` again. + +::: + +### Registering Settings + +Adding settings fields in this way is recommended for simple items. As a rule of thumb, if you only need to store things in the settings table, this should be enough for you. + +To add a field, call the `registerSetting` function after `for` on `app.extensionData` and pass a 'setting object' as the first argument. Behind the scenes `ExtensionData` actually turns your settings into an [`ItemList`](https://api.docs.flarum.org/js/master/class/src/common/utils/itemlist.ts~itemlist), you can pass a priority number as the second argument. + +Here's an example with a switch (boolean) item: + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerSetting( + { + setting: 'acme-interstellar.coordinates', // This is the key the settings will be saved under in the settings table in the database. + label: app.translator.trans('acme-interstellar.admin.coordinates_label'), // The label to be shown letting the admin know what the setting does. + help: app.translator.trans('acme-interstellar.admin.coordinates_help'), // Optional help text where a longer explanation of the setting can go. + type: 'boolean', // What type of setting this is, valid options are: boolean, text (or any other tag type), and select. + }, + 30 // Optional: Priority + ) +}); +``` + +If you use `type: 'select'` the setting object looks a little bit different: + +```js +{ + setting: 'acme-interstellar.fuel_type', + label: app.translator.trans('acme-interstellar.admin.fuel_type_label'), + type: 'select', + options: { + 'LOH': 'Liquid Fuel', // The key in this object is what the setting will be stored as in the database, the value is the label the admin will see (remember to use translations if they make sense in your context). + 'RDX': 'Solid Fuel', + }, + default: 'LOH', +} +``` + +Also, note that additional items in the setting object will be used as component attrs. This can be used for placeholders, min/max restrictions, etc: + +```js +{ + setting: 'acme-interstellar.crew_count', + label: app.translator.trans('acme-interstellar.admin.crew_count_label'), + type: 'number', + min: 1, + max: 10 +} +``` + +If you want to add something to the settings like some extra text or a more complicated input, you can also pass a callback as the first argument that returns JSX. This callback will be executed in the context of [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) and setting values will not be automatically serialized. + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerSetting(function () { + if (app.session.user.username() === 'RocketMan') { + + return ( +
+

{app.translator.trans('acme-interstellar.admin.you_are_rocket_man_label')}

+ +
+ ); + } + }) +}); +``` + +### Registering Permissions + +New in beta 15, permissions can now be found in 2 places. Now, you can view each extension's individual permissions on their page. All permissions can still be found on the permissions page. + +In order for that to happen, permissions must be registered with `ExtensionData`. This is done in a similar way to settings, call `registerPermission`. + +Arguments: + * Permission object + * What type of permission - see [`PermissionGrid`](https://api.docs.flarum.org/js/master/class/src/admin/components/permissiongrid.js~permissiongrid)'s functions for types (remove items from the name) + * `ItemList` priority + +Back to our favorite rocket extension: + +```js +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerPermission( + { + icon: 'fas fa-rocket', // Font-Awesome Icon + label: app.translator.trans('acme-interstellar.admin.permissions.fly_rockets_label'), // Permission Label + permission: 'discussion.rocket_fly', // Actual permission name stored in database (and used when checking permission). + tagScoped: true, // Whether it be possible to apply this permission on tags, not just globally. Explained in the next paragraph. + }, + 'start', // Category permission will be added to on the grid + 95 // Optional: Priority + ); +}); +``` + +If your extension interacts with the [tags extension](https://github.com/flarum/tags) (which is fairly common), you might want a permission to be tag scopable (i.e. applied on the tag level, not just globally). You can do this by including a `tagScoped` attribute, as seen above. Permissions starting with `discussion.` will automatically be tag scoped unless `tagScoped: false` is indicated. + +To learn more about Flarum permissions, see [the relevant docs](permissions.md). + +### Chaining Reminder + +Remember these functions can all be chained like: + +```js +app.extensionData + .for('acme-interstellar') + .registerSetting(...) + .registerSetting(...) + .registerPermission(...) + .registerPermission(...); +``` + +### Extending/Overriding the Default Page + +Sometimes you have more complicated settings that mess with relationships, or just want the page to look completely different. In this case, you will need to tell `ExtensionData` that you want to provide your own page. Note that `buildSettingComponent`, the util used to register settings by providing a descriptive object, is available as a method on `ExtensionPage` (extending from `AdminPage`, which is a generic base for all admin pages with some util methods). + +Create a new class that extends the `Page` or `ExtensionPage` component: + +```js +import ExtensionPage from 'flarum/admin/components/ExtensionPage'; + +export default class StarPage extends ExtensionPage { + content() { + return ( +

Hello from the settings section!

+ ) + } +} + +``` + +Then, simply run `registerPage`: + +```js + +import StarPage from './components/StarPage'; + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerPage(StarPage); +}); +``` + +This page will be shown instead of the default. + +You can extend the [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) or extend the base `Page` and design your own! + +## Composer.json Metadata + +In beta 15, extension pages make room for extra info which is pulled from extensions' composer.json. + +For more information, see the [composer.json schema](https://getcomposer.org/doc/04-schema.md). + +| Description | Where in composer.json | +| ---------------------------------- | ------------------------------------------------------------ | +| discuss.flarum.org discussion link | "forum" key inside "support" | +| Documentation | "docs" key inside "support" | +| Support (email) | "email" key inside "support" | +| Website | "homepage" key | +| Donate | "funding" key block (Note: Only the first link will be used) | +| Source | "source" key inside "support" | diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md new file mode 100644 index 000000000..9c039fe49 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md @@ -0,0 +1,58 @@ +# API Throttling + +Flarum comes with a builtin `Flarum\Api\Middleware\ThrottleApi` [middleware](middleware.md) for throttling requests to the API. This runs on every API route, and extensions can add their own custom logic to throttle requests. + +:::caution Forumsrouten + +Some forum routes (login, register, forgot password, etc) work by calling an API route under the surface. The `ThrottleApi` middleware does not currently run for these requests, but that is planned for the future. + +::: + +## Custom Throttlers + +The format for a custom throttler is extremely simple: all you need is a closure or invokable class that takes the current request as an argument, and returns one of: + +- `false`: This explicitly bypasses throttling for this request, overriding all other throttlers +- `true`: This marks the request as to be throttled. +- `null`: This means that this throttler doesn't apply. Any other outputs will be ignored, with the same effect as `null`. + +Throttlers will be run on EVERY request, and are responsible for figuring out whether or not they apply. For example, consider Flarum's post throttler: + +```php +use DateTime; +use Flarum\Post\Post; + +function ($request) { + if (! in_array($request->getAttribute('routeName'), ['discussions.create', 'posts.create'])) { + return; + } + + $actor = $request->getAttribute('actor'); + + if ($actor->can('postWithoutThrottle')) { + return false; + } + + if (Post::where('user_id', $actor->id)->where('created_at', '>=', new DateTime('-10 seconds'))->exists()) { + return true; + } +}; +``` + +Throttlers can be added or removed via the `ThrottleApi` middleware in `extend.php`. For example: + +```php +set('throttleAll', function () { + return false; + }) + ->remove('bypassThrottlingAttribute'), + // Other extenders +]; +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/api.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/api.md new file mode 100644 index 000000000..073d858e1 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/api.md @@ -0,0 +1,353 @@ +# API and Data Flow + +In the [previous article](models.md), we learned how Flarum uses models to interact with data. Here, we'll learn how to get that data from the database to the JSON-API to the frontend, and all the way back again. + +:::info + +To use the built-in REST API as part of an integration, see [Consuming the REST API](../rest-api.md). + +::: + +## API Request Lifecycle + +Before we go into detail about how to extend Flarum's data API, it's worth thinking about the lifecycle of a typical API request: + +![Flarum API Flowchart](/en/img/api_flowchart.png) + +1. An HTTP request is sent to Flarum's API. Typically, this will come from the Flarum frontend, but external programs can also interact with the API. Flarum's API mostly follows the [JSON:API](https://jsonapi.org/) specification, so accordingly, requests should follow [said specification](https://jsonapi.org/format/#fetching). +2. The request is run through [middleware](middleware.md), and routed to the proper controller. You can learn more about controllers as a whole on our [routes and content documentation](routes.md). Assuming the request is to the API (which is the case for this section), the controller that handles the request will be a subclass of `Flarum\Api\AbstractSerializeController`. +3. Any modifications done by extensions to the controller via the [`ApiController` extender](#extending-api-controllers) are applied. This could entail changing sort, adding includes, changing the serializer, etc. +4. The `$this->data()` method of the controller is called, yielding some raw data that should be returned to the client. Typically, this data will take the form of a Laravel Eloquent model collection or instance, which has been retrieved from the database. That being said, the data could be anything as long as the controller's serializer can process it. Each controller is responsible for implementing its own `data` method. Note that for `PATCH`, `POST`, and `DELETE` requests, `data` will perform the operation in question, and return the modified model instance. +5. That data is run through any pre-serialization callbacks that extensions register via the [`ApiController` extender](#extending-api-controllers). +6. The data is passed through a [serializer](#serializers), which converts it from the backend, database-friendly format to the JSON:API format expected by the frontend. It also attaches any related objects, which are run through their own serializers. As we'll explain below, extensions can [add / override relationships and attributes](#attributes-and-relationships) at the serialization level. +7. The serialized data is returned as a JSON response to the frontend. +8. If the request originated via the Flarum frontend's `Store`, the returned data (including any related objects) will be stored as [frontend models](#frontend-models) in the frontend store. + +## API Endpoints + +We learned how to use models to interact with data, but we still need to get that data from the backend to the frontend. We do this by writing API Controller [routes](routes.md), which implement logic for API endpoints. + +As per the JSON:API convention, we'll want to add separate endpoints for each operation we support. Common operations are: + +- Listing instances of a model (possibly including searching/filtering) +- Getting a single model instance +- Creating a model instance +- Updating a model instance +- Deleting a single model instance + +We'll go over each type of controller shortly, but once they're written, you can add these five standard endpoints (or a subset of them) using the `Routes` extender: + +```php + (new Extend\Routes('api')) + ->get('/tags', 'tags.index', ListTagsController::class) + ->get('/tags/{id}', 'tags.show', ShowTagController::class) + ->post('/tags', 'tags.create', CreateTagController::class) + ->patch('/tags/{id}', 'tags.update', UpdateTagController::class) + ->delete('/tags/{id}', 'tags.delete', DeleteTagController::class) +``` + +:::caution + +Paths to API endpoints are not arbitrary! To support interactions with frontend models: + +- The path should either be `/prefix/{id}` for get/update/delete, or `/prefix` for list/create. +- the prefix (`tags` in the example above) must correspond to the JSON:API model type. You'll also use this model type in your serializer's `$type` attribute, and when registering the frontend model (`app.store.models.TYPE = MODEL_CLASS`). +- The methods must match the example above. + +Also, remember that route names (`tags.index`, `tags.show`, etc) must be unique! + +::: + +The `Flarum\Api\Controller` namespace contains a number of abstract controller classes that you can extend to easily implement your JSON-API resources. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically create your endpoint controllers: +```bash +$ flarum-cli make backend api-controller +``` + +::: + +### Listing Resources + +For the controller that lists your resource, extend the `Flarum\Api\Controller\AbstractListController` class. At a minimum, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a collection of models. The `data` method accepts the `Request` object and the tobscure/json-api `Document`. + +```php +use Flarum\Api\Controller\AbstractListController; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ListTagsController extends AbstractListController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + return Tag::all(); + } +} +``` + +#### Pagination + +You can allow the number of resources being **listed** to be customized by specifying the `limit` and `maxLimit` properties on your controller: + +```php + // The number of records included by default. + public $limit = 20; + + // The maximum number of records that can be requested. + public $maxLimit = 50; +``` + +You can then extract pagination information from the request using the `extractLimit` and `extractOffset` methods: + +```php +$limit = $this->extractLimit($request); +$offset = $this->extractOffset($request); + +return Tag::skip($offset)->take($limit); +``` + +To add pagination links to the JSON:API document, use the `Document::addPaginationLinks` method. + +#### Sorting + +You can allow the sort order of resources being **listed** to be customized by specifying the `sort` and `sortField` properties on your controller: + +```php + // The default sort field and order to use. + public $sort = ['name' => 'asc']; + + // The fields that are available to be sorted by. + public $sortFields = ['firstName', 'lastName']; +``` + +You can then extract sorting information from the request using the `extractSort` method. This will return an array of sort criteria which you can apply to your query: + +```php +use Illuminate\Support\Str; + +// ... + +$sort = $this->extractSort($request); +$query = Tag::query(); + +foreach ($sort as $field => $order) { + $query->orderBy(Str::snake($field), $order); +} + +return $query->get(); +``` + +#### Searching and Filtering + +Read our [searching and filtering](search.md) guide for more information! + +### Showing a Resource + +For the controller that shows a single resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the list controller, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a single model. We'll learn about serializers [in just a bit](#serializers). + +```php +use Flarum\Api\Controller\AbstractShowController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ShowTagController extends AbstractShowController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + return Tag::findOrFail($id); + } +} +``` + +### Creating a Resource + +For the controller that creates a resource, extend the `Flarum\Api\Controller\AbstractCreateController` class. This is the same as the show controller, except the response status code will automatically be set to `201 Created`. You can access the incoming JSON:API document body via `$request->getParsedBody()`: + +```php +use Flarum\Api\Controller\AbstractCreateController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class CreateTagController extends AbstractCreateController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $attributes = Arr::get($request->getParsedBody(), 'data.attributes'); + + return Tag::create([ + 'name' => Arr::get($attributes, 'name') + ]); + } +} +``` + +### Updating a Resource + +For the controller that updates a resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the create controller, you can access the incoming JSON:API document body via `$request->getParsedBody()`. + +### Deleting a Resource + +For the controller that deletes a resource, extend the `Flarum\Api\Controller\AbstractDeleteController` class. You only need to implement a `delete` method which enacts the deletion. The controller will automatically return an empty `204 No Content` response. + +```php +use Flarum\Api\Controller\AbstractDeleteController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; + +class DeleteTagController extends AbstractDeleteController +{ + protected function delete(Request $request) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + Tag::findOrFail($id)->delete(); + } +} +``` + +### Including Relationships + +To include relationships when **listing**, **showing**, or **creating** your resource, specify them in the `$include` and `$optionalInclude` properties on your controller: + +```php + // The relationships that are included by default. + public $include = ['user']; + + // Other relationships that are available to be included. + public $optionalInclude = ['discussions']; +``` + +You can then get a list of included relationships using the `extractInclude` method. This can be used to eager-load the relationships on your models before they are serialized: + +```php +$relations = $this->extractInclude($request); + +return Tag::all()->load($relations); +``` + +### Extending API Controllers + +It is possible to customize all of these options on _existing_ API controllers too via the `ApiController` extender + +```php +use Flarum\Api\Event\WillGetData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->setSerializer(MyDiscussionSerializer::class) + ->addInclude('user') + ->addOptionalInclude('posts') + ->setLimit(20) + ->setMaxLimit(50) + ->setSort(['name' => 'asc']) + ->addSortField('firstName') + ->prepareDataQuery(function ($controller) { + // Add custom logic here to modify the controller + // before data queries are executed. + }) +] +``` + +The `ApiController` extender can also be used to adjust data before serialization + +```php +use Flarum\Api\Event\WillSerializeData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->prepareDataForSerialization(function ($controller, $data, $request, $document) { + $data->load('myCustomRelation'); + }), +] +``` + +## Serializers + +Before we can send our data to the frontend, we need to convert it to JSON:API format so that it can be consumed by the frontend. You should become familiar with the [JSON:API specification](https://jsonapi.org/format/). Flarum's JSON:API layer is powered by the [tobscure/json-api](https://github.com/tobscure/json-api) library. + +A serializer is just a class that converts some data (usually [Eloquent models](models.md#backend-models)) into JSON:API. Serializers serve as intermediaries between backend and frontend models: see the [model documentation](models.md) for more information. To define a new resource type, create a new serializer class extending `Flarum\Api\Serializer\AbstractSerializer`. You must specify a resource `$type` and implement the `getDefaultAttributes` method which accepts the model instance as its only argument: + +```php +use Flarum\Api\Serializer\AbstractSerializer; +use Flarum\Api\Serializer\UserSerializer; + +class DiscussionSerializer extends AbstractSerializer +{ + protected $type = 'discussions'; + + protected function getDefaultAttributes($discussion) + { + return [ + 'title' => $discussion->title, + ]; + } +} +``` + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically create your serializer: +```bash +$ flarum-cli make backend api-serializer +``` + +::: + +### Attributes and Relationships + +You can also specify relationships for your resource. Simply create a new method with the same name as the relation on your model, and return a call to `hasOne` or `hasMany` depending on the nature of the relationship. You must pass in the model instance and the name of the serializer to use for the related resources. + +```php + protected function user($discussion) + { + return $this->hasOne($discussion, UserSerializer::class); + } +``` + +### Extending Serializers + +To add **attributes** and **relationships** to an existing resource type, use the `ApiSerializer` extender: + +```php +use Flarum\Api\Serializer\UserSerializer; + +return [ + (new Extend\ApiSerializer(UserSerializer::class)) + // One attribute at a time + ->attribute('firstName', function ($serializer, $user, $attributes) { + return $user->first_name + }) + // Multiple modifications at once, more complex logic + ->mutate(function($serializer, $user, $attributes) { + $attributes['someAttribute'] = $user->someAttribute; + if ($serializer->getActor()->can('administrate')) { + $attributes['someDate'] = $serializer->formatDate($user->some_date); + } + + return $attributes; + }) + // API relationships + ->hasOne('phone', PhoneSerializer::class) + ->hasMany('comments', CommentSerializer::class), +] +``` + +### Non-Model Serializers and `ForumSerializer` + +Serializers don't have to correspond to Eloquent models: you can define JSON:API resources for anything. For instance, Flarum core uses the [`Flarum\Api\Serializer\ForumSerializer`](https://api.docs.flarum.org/php/master/flarum/api/serializer/forumserializer) to send an initial payload to the frontend. This can include settings, whether the current user can perform certain actions, and other data. Many extensions add data to the payload by extending the attributes of `ForumSerializer`. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/assets.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/assets.md new file mode 100644 index 000000000..16b401fc3 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/assets.md @@ -0,0 +1,7 @@ +# Extension Assets + +Some extensions might want to include assets like images or JSON files in their source code (note that this is not the same as uploads, which would probably require a [filesystem disk](filesystem.md)). + +This is actually very easy to do. Just create an `assets` folder at the root of your extension, and place any asset files there. Flarum will then automatically copy those files to its own `assets` directory (or other storage location if [one is offered by extensions](filesystem.md)) every time the extension is enabled or [`php flarum assets:publish`](../console.md) is executed. + +If using the default storage driver, assets will be available at `https://FORUM_URL/assets/extensions/EXTENSION_ID/file.path`. However, since other extensions might use remote filesystems, we recommend serializing the url to assets you need in the backend. See [Flarum's serialization of the logo and favicon URLs](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Serializer/ForumSerializer.php#L85-L86) for an example. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md new file mode 100644 index 000000000..338bbd06f --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md @@ -0,0 +1,206 @@ +# Authorization + +As with any framework, Flarum allows certain actions and content to be restricted to certain users. There are 2 parallel systems for this: + +- The authorization process dictates whether a user can take a certain action. +- Visibility scoping can be applied to a database query to efficiently restrict the records that users can access. This is documented in our [model visibility](model-visibility.md) article. + +## Authorization Process + +The authorization process is used to check whether a person is allowed to perform certain actions. For instance, we want to check if a user is authorized before they: + +- Access the admin dashboard +- Start a discussion +- Edit a post +- Update another user's profile + +Each of these is determined by unique criteria: in some cases a flag is sufficient; otherwise, we might need custom logic. + +## How It Works + +Authorization queries are made with 3 parameters, with logic contained in [`Flarum\User\Gate`](https://api.docs.flarum.org/php/master/flarum/user/access/gate): + +1. The actor: the user attempting to perform the action +2. The ability: a string representing the action the actor is attempting +3. The arguments: usually an instance of a database model which is the subject of the attempted ability, but could be anything. + +First, we run the entire request (all three parameters) through all [policies](#policies) registered by extensions and core. Policies are blocks of logic provided by core and extensions that determine whether the actor can perform the ability on the arguments. Policies can return one of the following: + +- `Flarum\User\Access\AbstractPolicy::ALLOW` (via `$this->allow()`) +- `Flarum\User\Access\AbstractPolicy::DENY` (via `$this->deny()`) +- `Flarum\User\Access\AbstractPolicy::FORCE_ALLOW` (via `$this->forceAllow()`) +- `Flarum\User\Access\AbstractPolicy::FORCE_DENY` (via `$this->forceDeny()`) + +Policy results are considered in the priority `FORCE_DENY` > `FORCE_ALLOW` > `DENY` > `ALLOW`. For example, if a single policy returns `FORCE_DENY`, all other policies will be ignored. If one policy returns `DENY` and 10 policies return `ALLOW`, the request will be denied. This allows decisions to be made regardless of the order in which extensions are booted. Note that policies are extremely powerful: if access is denied at the policy stage, that will override group permissions and even admin privileges. + +Secondly, if all policies return null (or don't return anything), we check if the user is in a group that has a permission equal to the ability (note that both permissions and abilities are represented as strings). If so, we authorize the action. See our [Groups and Permissions documentation](permissions.md) for more information on permissions. + +Then, if the user is in the admin group, we will authorize the action. + +Finally, as we have exhausted all checks, we will assume that the user is unauthorized and deny the request. + +## How To Use Authorization + +Flarum's authorization system is accessible through public methods of the `Flarum\User\User` class. The most important ones are listed below; others are documented in our [PHP API documentation](https://api.docs.flarum.org/php/master/flarum/user/user). + + +In this example, we will use `$actor` as an instance of `Flarum\User\User`, `'viewForum'` and `'reply'` as examples of abilities, and `$discussion` (instance of `Flarum\Discussion\Discussion`) as an example argument. + +```php +// Check whether a user can perform an action. +$canDoSomething = $actor->can('viewForum'); + +// Check whether a user can perform an action on a subject. +$canDoSomething = $actor->can('reply', $discussion); + +// Raise a PermissionDeniedException if a user cannot perform an action. +$actor->assertCan('viewForum'); +$actor->assertCan('reply', $discussion); + +// Raise a NotAuthenticatedException if the user is not logged in. +$actor->assertRegistered(); + +// Raise a PermissionDeniedException if the user is not an admin. +$actor->assertAdmin(); + +// Check whether one of the user's groups have a permission. +// WARNING: this should be used with caution, as it doesn't actually +// run through the authorization process, so it doesn't account for policies. +// It is, however, useful in implementing custom policies. +$actorHasPermission = $actor->hasPermission(`viewForum`); +``` + +## Custom Policies + +Policies allow us to use custom logic beyond simple groups and permissions when evaluating authorization for an ability with a subject. For instance: + +- We want to allow users to edit posts even if they aren't moderators, but only their own posts. +- Depending on settings, we might allow users to rename their own discussions indefinitely, for a short period of time after posting, or not at all. + +As described [above](#how-it-works), on any authorization check, we query all policies registered for the target's model, or any parent classes of the target's model. If no target is provided, any policies registered as `global` will be applied. + +So, how does a policy get "checked"? + +First, we check if the policy class has a method with the same name as the ability being evaluated. If so, we run it with the actor and subject as parameters. If that method returns a non-null value, we return that result. Otherwise, we continue to the next step (not necessarily the next policy). + +Then, we check if the policy class has a method called `can`. If so, we run it with the actor, ability, and subject, and return the result. + +If `can` doesn't exist or returns null, we are done with this policy, and we proceed to the next one. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate policies: +```bash +$ flarum-cli make backend policy +``` + +::: + +### Example Policies + +Let's take a look at an example policy from [Flarum Tags](https://github.com/flarum/tags/blob/master/src/Access): + +```php +is_restricted) { + return $actor->hasPermission('tag'.$tag->id.'.startDiscussion') ? $this->allow() : $this->deny(); + } + } + + /** + * @param User $actor + * @param Tag $tag + * @return bool|null + */ + public function addToDiscussion(User $actor, Tag $tag) + { + return $this->startDiscussion($actor, $tag); + } +} +``` + +We can also have global policies, which are run when `$user->can()` is called without a target model instance. Again from Tags: + +```php +settings = $settings; + } + + /** + * @param Flarum\User\User $actor + * @param string $ability + * @return bool|void + */ + public function can(User $actor, string $ability) + { + if (in_array($ability, ['viewForum', 'startDiscussion'])) { + $enoughPrimary = count(Tag::getIdsWhereCan($actor, $ability, true, false)) >= $this->settings->get('min_primary_tags'); + $enoughSecondary = count(Tag::getIdsWhereCan($actor, $ability, false, true)) >= $this->settings->get('min_secondary_tags'); + + if ($enoughPrimary && $enoughSecondary) { + return $this->allow(); + } else { + return $this->deny(); + } + } + } +} +``` + +### Registering Policies + +Both model-based and global policies can be registered with the `Policy` extender in your `extend.php` file: + +```php +use Flarum\Extend; +use Flarum\Tags\Tag; +use YourNamespace\Access; + +return [ + // Other extenders + (new Extend\Policy()) + ->modelPolicy(Tag::class, Access\TagPolicy::class) + ->globalPolicy(Access\GlobalPolicy::class), + // Other extenders +]; +``` + +## Frontend Authorization + +Commonly, you'll want to use authorization results in frontend logic. For example, if a user doesn't have permission to see search users, we shouldn't send requests to that endpoint. And if a user doesn't have permission to edit users, we shouldn't show menu items for that. + +Because we can't do authorization checks in the frontend, we have to perform them in the backend, and attach them to serialization of data we're sending. Global permissions (`viewForum`, `viewUserList`) can be included on the `ForumSerializer`, but for object-specific authorization, we may want to include those with the subject object. For instance, when we return lists of discussions, we check whether the user can reply, rename, edit, and delete them, and store that data on the frontend discussion model. It's then accessible via `discussion.canReply()` or `discussion.canEdit()`, but there's nothing magic there: it's just another attribute sent by the serializer. + +For an example of how to attach data to a serializer, see a [similar case for transmitting settings](settings.md#accessing-settings). diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md new file mode 100644 index 000000000..25142b030 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md @@ -0,0 +1,172 @@ +# Backend Events + +Often, an extension will want to react to some events occuring elsewhere in Flarum. For instance, we might want to increment a counter when a new discussion is posted, send a welcome email when a user logs in for the first time, or add tags to a discussion before saving it to the database. These events are known as **domain events**, and are broadcasted across the framework through [Laravel's event system](https://laravel.com/docs/8.x/events). + +For a full list of backend events, see our [API documentation](https://api.docs.flarum.org/php/master/search.html?search=Event). Domain events classes are organized by namespace, usually `Flarum\TYPE\Event`. + + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate event listeners: +```bash +$ flarum-cli make backend event-listener +``` + +::: + +## Listening to Events + +You can attach a listener to an event using the [`Event`](https://api.docs.flarum.org/php/master/flarum/extend/event) [extender](start.md#extenders): + +```php +use Flarum\Extend; +use Flarum\Post\Event\Deleted; +use Symfony\Contracts\Translation\TranslatorInterface; + + +return [ + (new Extend\Event) + ->listen(Deleted::class, function($event) { + // do something here + }) + ->listen(Deleted::class, PostDeletedListener::class) +]; +``` +```php +class PostDeletedListener +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function handle(Deleted $event) + { + // Your logic here + } +} +``` + +As shown above, a listener class can be used instead of a callback. This allows you to [inject dependencies](https://laravel.com/docs/8.x/container) into your listener class via constructor parameters. In this example we resolve a translator instance, but we can inject anything we want/need. + +You can also listen to multiple events at once via an event subscriber. This is useful for grouping common functionality; for instance, if you want to update some metadata on changes to posts: + +```php +use Flarum\Extend; +use Flarum\Post\Event\Deleted; +use Flarum\Post\Event\Saving; +use Symfony\Contracts\Translation\TranslatorInterface; + + +return [ + (new Extend\Event) + ->subscribe(PostEventSubscriber::class), +]; +``` +```php +class PostEventSubscriber +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function subscribe($events) + { + $events->listen(Deleted::class, [$this, 'handleDeleted']); + $events->listen(Saving::class, [$this, 'handleSaving']); + } + + public function handleDeleted(Deleted $event) + { + // Your logic here + } + + public function handleSaving(Saving $event) + { + // Your logic here + } +} +``` + +## Dispatching Events + +Dispatching events is very simple. All you need to do is inject `Illuminate\Contracts\Events\Dispatcher` into your class, and then call its `dispatch` method. For instance: + +```php +use Flarum\Post\Event\Deleted; +use Illuminate\Contracts\Events\Dispatcher; + + +class SomeClass +{ + /** + * @var Dispatcher + */ + protected $events; + + /** + * @param Dispatcher $events + */ + public function __construct(Dispatcher $events) + { + $this->events = $events; + } + + public function someMethod() + { + // Logic + $this->events->dispatch( + new Deleted($somePost, $someActor) + ); + // More Logic + } +} +``` + +## Custom Events + +As an extension developer you can define your own events to allow yourself (or other extensions) to react to events in your extension. Events are generally instances of simple classes (no need to extend anything). When defining a new event, you'll typically want to use public properties, and maybe some methods for convenience of users. For example, if we take a look at `Flarum\Post\Event\Deleted`, it's just a wrapping around some data: + +```php +post = $post; + $this->actor = $actor; + } +} +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/cli.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/cli.md new file mode 100644 index 000000000..ee92962b8 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/cli.md @@ -0,0 +1,15 @@ +# Flarum CLI + +The Flarum development ecosystem is oriented around many small, modules, interacting extensions. This is a very powerful and flexible paradigm, but it also brings the maintenance cost of creating and maintaining all these extensions. + +We've created the Flarum CLI (command line interface) as a tool to help developers by automating some repetitive and menial tasks, and allow them to get into the actual work without much hassle. + +Major updates about Flarum CLI will be published [on this discussion](https://discuss.flarum.org/d/28427-flarum-cli-v10). + +See the [package's readme](https://github.com/flarum/cli#readme) for information on: + +- Installation +- Usage +- Upgrading +- Available commands +- Some implementation details, if you're interested diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/console.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/console.md new file mode 100644 index 000000000..31aa2b87d --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/console.md @@ -0,0 +1,70 @@ +# Konsole + +Flarum allows extension developers to add custom console commands in addition to the [default ones](../console.md) provided by flarum core. + +All console command development is done in the backend using PHP. To create a custom console command, you'll need to create a class that extends `\Flarum\Console\AbstractCommand`. + +```php +use Flarum\Console\AbstractCommand; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; + +class YourCommand extends AbstractCommand { + protected function configure() + { + $this + ->setName('YOUR COMMAND NAME') + ->setDescription('YOUR COMMAND DESCRIPTION'); + } + protected function fire() + { + // Your logic here! + } +} +``` + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate and register a console command: +```bash +$ flarum-cli make backend command +``` + +::: + +## Registering Console Commands + +To register console commands, use the `Flarum\Extend\Console` extender in your extension's `extend.php` file: + +```php +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; + +return [ + // Other extenders + (new Extend\Console())->command(CustomCommand::class) + // Other extenders +]; +``` + +## Scheduled Commands + +The `Flarum\Extend\Console`'s `schedule` method allows extension developers to create scheduled commands that run on an interval: + + +```php +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; +use Illuminate\Console\Scheduling\Event; + +return [ + // Other extenders + (new Extend\Console())->schedule('cache:clear', function (Event $event) { + $event->everyMinute(); + }, ['Arg1', '--option1', '--option2']), + // Other extenders +]; +``` + +In the callback provided as the second argument, you can call methods on the [$event object](https://laravel.com/api/8.x/Illuminate/Console/Scheduling/Event.html) to schedule on a variety of frequencies (or apply other options, such as only running on one server). See the [Laravel documentation](https://laravel.com/docs/8.x/scheduling#scheduling-artisan-commands) for more information. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md new file mode 100644 index 000000000..7061d5aa0 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md @@ -0,0 +1,40 @@ +# Distribution + +You've written a great extension — and now you want the whole world to be able to use it. This document will take you through the process of distribution, from setting up a Git repository for your extension, to publishing it on Packagist. + +## Setting Up Git + +The first thing you'll need to do is set up a version control system (VCS). The most popular VCS is [Git](https://git-scm.com/). In this guide we'll be using Git, so make sure you have it [installed](https://git-scm.com/downloads) before continuing. If you don't have much Git knowledge, you may want to check out [these learning resources](https://try.github.io/). + +After you have installed Git, you'll need to initialize your repository. You can use `git init` on the command line if you're comfortable, or use a GUI tool like [SourceTree](https://www.sourcetreeapp.com/) or [GitKraken](https://www.gitkraken.com/). + +Then, you'll need an account in a Git hosting server, the most popular being [GitHub](https://github.com) and [GitLab](https://gitlab.com). These will instruct you on how to hook up your local repository with the online "remote" repository. + +## Tagging a Release + +As you are going to be publishing this extension, you'll want to make sure that the information is up to date. Take a minute to revisit `composer.json` and make sure package name, description, and Flarum extension information are all correct. It is recommended to have a `README.md` file in your repository to explain what the extension is, so create one if you haven't already. + +When you're ready to release, commit your extension's files to the repo and tag your first version: + +```bash +git tag v0.1.0 +git push && git push --tags +``` + +## Publishing on Packagist + +Composer packages are published to a Composer repository, usually [Packagist](https://packagist.org/). You will need an account to proceed. + +If this is the first release you are publishing of your extension, you will need to [submit your package](https://packagist.org/packages/submit) using its public repository URL. If your extension is located on GitHub, this URL will look something like `https://github.com/AUTHOR/NAME.git`. + +### Future Releases + +You can set up Packagist to [auto-update packages](https://packagist.org/about#how-to-update-packages). Then for future releases, all you will need to do with Git is commit, tag, and push it to the remote server. + +## Promoting Your Extension + +You will most likely want to create a discussion on the Flarum Community in the [Extensions tag](https://discuss.flarum.org/t/extensions). Other people can install your extension using the following command: + +```bash +composer require vendor/package +``` \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md new file mode 100644 index 000000000..7a8db4f8c --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md @@ -0,0 +1,122 @@ +# Extending Extensions + +Flarum extensions aren't just for adding features to core: extensions can extend other extensions! + +:::tip + +To learn how to make your extension extensible, see the [relevant documentation](extensibility.md) + +::: + +## Dependencies + +If your extension relies on another extension, you'll want to ensure that: + +- The other extension is installed and enabled before yours can be. +- The other extension can't be disabled while yours is enabled. +- The other extension is booted before your extension. + +Flarum makes this very easy: just add the other extension to your extension's `composer.json`'s `require` section. + +For example, if you were building a new theme for the Flarum Tags extension, your `composer.json` would look like this: + +```json +{ + // ... + "require": { + "flarum/core": "^0.1.0-beta.15", // Since all extensions need to require core. + "flarum/tags": "^0.1.0-beta.15" // This tells Flarum to treat tags as a dependency of your extension. + }, + // ... +} +``` + +## Optional Dependencies + +Sometimes, extension A might want to extend extension B only if extension B is enabled. In this case, we call B an "Optional Dependency" of A. For instance, a drafts extension might want to add support for saving private discussion drafts, but only if the private discussion extension is enabled. + +The first step here is detecting whether extension B is enabled. In the frontend, this is easy: if extension B does anything in the frontend, its extension ID will appear as a key in the `flarum.extensions` global object. For instance: + +```js +if ('some-extension-id' in flarum.extensions) { + // do something +} +``` + +In the backend, you'll need to inject an instance of `Flarum\Extension\ExtensionManager`, and use its `isEnabled()` method. For instance: + +```php +extensions = $extensions; + } + + public function someMethod() + { + if ($this->extensions->isEnabled('some-extension-id')) { + // do something. + } + } +} +``` + +Generally, if your extension has optional dependencies, you'll want it to be booted after said optional dependencies. You can also do this by specifying composer package names (NOT flarum extension IDs) in an array for the `extra.flarum-extension.optional-dependencies` key of your composer.json. + +For instance: + +```json +{ + // ... + "extra": { + "flarum-extension": { + "optional-dependencies": [ + "flarum/tags" + ] + } + }, + // ... +} +``` + +## Importing from Extensions + +In the backend, you can import the classes you need via regular PHP `use` statements: + +```php + { + // Your Extension Code Here +}) + +export { + // Put all the stuff you want to export here. +} +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md new file mode 100644 index 000000000..ef202b2c7 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md @@ -0,0 +1,129 @@ +# Filesystem + +Flarum core integrates with the filesystem to store and serve assets (like compiled JS/CSS or upload logos/favicons) and avatars. + +Extensions can use Flarum's provided utils for their own filesystem interaction and file storage needs. This system is based around [Laravel's filesystem tools](https://laravel.com/docs/8.x/filesystem), which are in turn based on the [Flysystem library](https://github.com/thephpleague/flysystem). + +## Disks + +Filesystem **disks** represent storage locations, and are backed by storage drivers, which we'll cover later. Flarum core has 2 disks: `flarum-assets` and `flarum-avatars`. + +### Using existing disks + +To access a disk, you'll need to retrieve it from the [Filesystem Factory](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Factory.html). To do so, you should inject the factory contract in your class, and access the disks you need. + +Let's take a look at core's [`DeleteLogoController`](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Controller/DeleteLogoController.php#L19-L58) for an example: + +```php +settings = $settings; + $this->uploadDir = $filesystemFactory->disk('flarum-assets'); + } + + /** + * {@inheritdoc} + */ + protected function delete(ServerRequestInterface $request) + { + RequestUtil::getActor($request)->assertAdmin(); + + $path = $this->settings->get('logo_path'); + + $this->settings->set('logo_path', null); + + if ($this->uploadDir->exists($path)) { + $this->uploadDir->delete($path); + } + + return new EmptyResponse(204); + } +} +``` + +The object returned by `$filesystemFactory->disk(DISK_NAME)` implements the [Illuminate\Contracts\Filesystem\Cloud](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Cloud.html) interface, and can be used to create/get/move/delete files, and to get the URL to a resource. + +### Declaring new disks + +Some extensions will want to group their resources / uploads onto a custom disk as opposed to using `flarum-assets` or `flarum-avatars`. + +This can be done via the `Filesystem` extender: + +```php +use Flarum\Extend; + +return [ + (new Extend\Filesystem) + ->disk('flarum-uploads', function (Paths $paths, UrlGenerator $url) { + return [ + 'root' => "$paths->public/assets/uploads", + 'url' => $url->to('forum')->path('assets/uploads') + ]; + }); +``` + +Since all disks use the local filesystem by default, you'll need to provide a base path and base URL for the local filesystem. + +The config array can contain other entries supported by [Laravel disk config arrays](https://laravel.com/docs/8.x/filesystem#configuration). The `driver` key should not be provided, and will be ignored. + +## Storage drivers + +Flarum selects the active driver for each disk by checking the `disk_driver.DISK_NAME` key in the [settings repository](settings.md) and [config.php file](../config.md). If no driver is configured, or the configured driver is unavailable, Flarum will default to the `local` driver. + +You can define new storage drivers by implementing the [`Flarum\Filesystem\DriverInterface` interface](https://github.com/flarum/framework/blob/main/framework/core/src/Filesystem/DriverInterface.php#L16), and registering it via the `Filesystem` extender: + +```php +use Flarum\Extend; + +return [ + (new Extend\Filesystem) + ->driver('aws-with-cdn', AwsWithCdnDriver::class); +``` + +Filesystem storage drivers are a very powerful tool that allows you to completely customize file storage locations, attach arbitrary CDNs, and otherwise extend the filesystem / cloud storage integration layer. + +:::danger + +Some drivers might try to index their filesystem every time the driver is instantiated, even if only the `url` method is needed. This can have serious performance implications. In most cases, you'll want to ensure that your driver's `url` method does not ping the remote filesystem. Similarly, the remote filesystem should usually not be accessed until operations are actually executed. + +::: + +## GUI and Admin Configuration + +Flarum does not currently provide a GUI for selecting drivers for disks, or for entering settings for drivers. This might be added in the future. For now, extensions are responsible for providing a GUI for their disks and drivers. + +As noted [above](#storage-drivers), if your extension provides a GUI for selecting drivers for a disk, it should modify the `disk_driver.DISK_NAME` key in settings. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md new file mode 100644 index 000000000..d4ea23b12 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md @@ -0,0 +1,42 @@ +# Formatting + +Flarum uses the powerful [s9e TextFormatter](https://github.com/s9e/TextFormatter) library to format posts from plain markup into HTML. You should become familiar with [how TextFormatter works](https://s9etextformatter.readthedocs.io/Getting_started/How_it_works/) before you attempt to extend it. + +In Flarum, post content is formatted with a minimal TextFormatter configuration by default. The bundled **Markdown** and **BBCode** extensions simply enable the respective plugins on this TextFormatter configuration. + +## Configuration + +You can configure the TextFormatter `Configurator` instance, as well as run custom logic during parsing and rendering, using the `Formatter` extender: + +```php +use Flarum\Extend; +use Psr\Http\Message\ServerRequestInterface as Request; +use s9e\TextFormatter\Configurator; +use s9e\TextFormatter\Parser; +use s9e\TextFormatter\Renderer; + +return [ + (new Extend\Formatter) + // Add custom text formatter configuration + ->configure(function (Configurator $config) { + $config->BBCodes->addFromRepository('B'); + }) + // Modify raw text before it is parsed. + // This callback should return the modified text. + ->parse(function (Parser $parser, $context, $text) { + // custom logic here + return $newText; + }) + // Modify the XML to be rendered before rendering. + // This callback should return the new XML. + // For example, in the mentions extension, this is used to + // provide the username and display name of the user being mentioned. + // Make sure that the last $request argument is nullable (or omitted entirely). + ->render(function (Renderer $renderer, $context, $xml, Request $request = null) { + // custom logic here + return $newXml; + }) +]; +``` + +With a good understanding of TextFormatter, this will allow you to achieve anything from simple BBCode tag additions to more complex formatting tasks like Flarum's **Mentions** extension. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/forms.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/forms.md new file mode 100644 index 000000000..af8d74fb6 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/forms.md @@ -0,0 +1,108 @@ +# Forms and Requests + +In this article, we'll go over some frontend tools that are available to us for building and managing forms, as well how to send HTTP requests via Flarum. + +## Form Components + +As with any interactive site, you will likely want to include forms in some pages and modals. Flarum provides some components to make building (and styling!) these forms easier. Please see the linked API documentation for each of these to learn more about its accepted attrs. + +- The [`flarum/common/components/FieldSet` component](https://api.docs.flarum.org/js/master/class/src/common/components/fieldset.js~fieldset) wraps its children in a HTML fieldset tag, with a legend. +- The [`flarum/common/components/Select` component](https://api.docs.flarum.org/js/master/class/src/common/components/select.js~select) is a stylized select input. +- The [`flarum/common/components/Switch`](https://api.docs.flarum.org/js/master/class/src/common/components/switch.js~switch) and [`flarum/common/components/Checkbox` components](https://api.docs.flarum.org/js/master/class/src/common/components/checkbox.js~checkbox) are stylized checkbox input components. Their `loading` attr can be set to `true` to show a loading indicator. +- The [`flarum/common/components/Button` component](https://api.docs.flarum.org/js/master/class/src/common/components/button.js~button) is a stylized button, and is used frequently throughout Flarum. + +You'll typically want to assign logic for reacting to input changes via Mithril's `on*` attrs, not external listeners (as is common with jQuery or plain JS). For example: + +```jsx +import Component from 'flarum/common/Component'; +import FieldSet from 'flarum/common/components/FieldSet'; +import Button from 'flarum/common/components/Button'; +import Switch from 'flarum/common/components/Switch'; + + +class FormComponent extends Component { + oninit(vnode) { + this.textInput = ""; + this.booleanInput = false; + } + + view() { + return ( +
+
+ this.textInput = e.target.value}> + + this.booleanInput = val}> + +
+ +
+ ) + } + + onsubmit() { + // Some form handling logic here + } +} +``` + +Don't forget to use [translations](i18n.md)! + + +## Streams, bidi, and withAttr + +Flarum provides [Mithril's Stream](https://mithril.js.org/stream.html) as `flarum/common/util/Stream`. This is a very powerful reactive data structure, but is most commonly used in Flarum as a wrapper for form data. Its basic usage is: + +```js +import Stream from 'flarum/common/utils/Stream'; + + +const value = Stream("hello!"); +value() === "hello!"; // true +value("world!"); +value() === "world!"; // true +``` + +In Flarum forms, streams are frequently used together with the bidi attr. Bidi stands for bidirectional binding, and is a common pattern in frontend frameworks. Flarum patches Mithril with the [`m.attrs.bidi` library](https://github.com/tobyzerner/m.attrs. This abstracts away input processing in Mithril. For instance: + +```jsx +import Stream from 'flarum/common/utils/Stream'; + +const value = Stream(); + +// Without bidi + value(e.target.value)}> + +// With bidi + +``` + +You can also use the `flarum/common/utils/withAttr` util for simplified form processing. `withAttr` calls a callable, providing as an argument some attr of the DOM element tied to the component in question: + +```jsx +import Stream from 'flarum/common/utils/Stream'; +import withAttr from 'flarum/common/utils/withAttr'; + +const value = Stream(); + +// With a stream + + +// With any callable + { + // Some custom logic here +})}> +``` + +## Making Requests + +In our [models](models.md) documentation, you learned how to work with models, and save model creation, changes, and deletion to the database via the Store util, which is just a wrapper around Flarum's request system, which itself is just a wrapper around [Mithril's request system](https://mithril.js.org/request.html). + +Flarum's request system is available globally via `app.request(options)`, and has the following differences from Mithril's `m.request(options)`: + +- It will automatically attach `X-CSRF-Token` headers. +- It will convert `PATCH` and `DELETE` requests into `POST` requests, and attach a `X-HTTP-Method-Override` header. +- If the request errors, it will show an alert which, if in debug mode, can be clicked to show a full error modal. +- You can supply a `background: false` option, which will run the request synchronously. However, this should almost never be done. + +Otherwise, the API for using `app.request` is the same as that for `m.request`. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md new file mode 100644 index 000000000..396292ad1 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md @@ -0,0 +1,218 @@ +# Frontend Pages and Resolvers + +As explained in the [Routes and Content](routes.md#frontend-routes) documentation, we can use Mithril's routing system to show different [components](frontend.md#components) for different routes. Mithril allows you to use any component you like, even a Modal or Alert, but we recommend sticking to component classes that inherit the `Page` component. + +## The Page Component + +We provide `flarum/common/components/Page` as a base class for pages in both the `admin` and `forum` frontends. It has a few benefits: + +- Automatically updates [`app.current` and `app.previous` PageState](#pagestate) when switching from one route to another. +- Automatically closes the modal and drawer when switching from one route to another. +- Applies `this.bodyClass` (if defined) to the '#app' HTML element when the page renders. +- It's also good for consistency's sake to use a common base class for all pages. +- If the page's `scrollTopOnCreate` attribute is set to `false` in `oninit`, the page won't be scrolled to the top when changed. +- If the page's `useBrowserScrollRestoration` is set to `false` in `oninit`, the browser's automatic scroll restoration won't be used on that page. + +Page components work just like any other inherited component. For a (very simple) example: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + view() { + return

Hello!

+ } +} +``` + +### Setting Page as Homepage + +Flarum uses a setting to determine which page should be the homepage: this gives admins flexibility to customize their communities. To add your custom page to the homepage options in Admin, you'll need to extend the `BasicsPage.homePageItems` method with your page's path. + +An example from the [Tags extension](https://github.com/flarum/tags/blob/master/js/src/admin/addTagsHomePageOption.js): + +```js +import { extend } from 'flarum/common/extend'; +import BasicsPage from 'flarum/common/components/BasicsPage'; + +export default function() { + extend(BasicsPage.prototype, 'homePageItems', items => { + items.add('tags', { + path: '/tags', + label: app.translator.trans('flarum-tags.admin.basics.tags_label') + }); + }); +} +``` + +To learn how to set up a path/route for your custom page, see the [relevant documentation](routes.md). + +### Page Titles + +Often, you'll want some custom text to appear in the browser tab's title for your page. For instance, a tags page might want to show "Tags - FORUM NAME", or a discussion page might want to show the title of the discussion. + +To do this, your page should include calls to `app.setTitle()` and `app.setTitleCount()` in its `oncreate` [lifecycle hook](frontend.md) (or when data is loaded, if it pulls in data from the API). + +For example: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + oncreate(vnode) { + super.oncreate(vnode); + + app.setTitle("Cool Page"); + app.setTitleCount(0); + } + + view() { + // ... + } +} + +export default class CustomPageLoadsData extends Page { + oninit(vnode) { + super.oninit(vnode); + + app.store.find("users", 1).then(user => { + app.setTitle(user.displayName()); + app.setTitleCount(0); + }) + } + + view() { + // ... + } +} +``` + +Please note that if your page is [set as the homepage](#setting-page-as-homepage), `app.setTitle()` will clear the title for simplicity. It should still be called though, to prevent titles from previous pages from carrying over. + +## PageState + +Sometimes, we want to get information about the page we're currently on, or the page we've just come from. To allow this, Flarum creates (and stores) instances of [`PageState`](https://api.docs.flarum.org/js/master/class/src/common/states/pagestate.js~pagestate) as `app.current` and `app.previous`. These store: + +- The component class being used for the page +- A collection of data that each page sets about itself. The current route name is always included. + +Data can be set to, and retrieved from, Page State using: + +```js +app.current.set(KEY, DATA); +app.current.get(KEY); +``` + +For example, this is how the Discussion Page makes its [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) instance globally available. + +You can also check the type and data of a page using `PostStreamState`'s `matches` method. For instance, if we want to know if we are currently on a discussion page: + +```jsx +import IndexPage from 'flarum/forum/components/DiscussionPage'; +import DiscussionPage from 'flarum/forum/components/DiscussionPage'; + +// To just check page type +app.current.matches(DiscussionPage); + +// To check page type and some data +app.current.matches(IndexPage, {routeName: 'following'}); +``` + +## Admin Pages + +See the [Admin Dashboard documentation](admin.md) for more information on tools specifically available to admin pages (and how to override the admin page for your extension). + +## Route Resolvers (Advanced) + +[Advanced use cases](https://mithril.js.org/route.html#advanced-component-resolution) can take advantage of Mithril's [route resolver system](https://mithril.js.org/route.html#routeresolver). Flarum actually already wraps all its components in the `flarum/common/resolvers/DefaultResolver` resolver. This has the following benefits: + +- It passes a `routeName` attr to the current page, which then provides it to `PageState` +- It assigns a [key](https://mithril.js.org/keys.html#single-child-keyed-fragments) to the top level page component. When the route changes, if the top level component's key has changed, it will be completely rerendered (by default, Mithril does not rerender components when switching from one page to another if both are handled by the same component). + +### Using Route Resolvers + +There are actually 3 ways to set the component / route resolver when registering a route: + +- the `resolver` key can be used to provide an **instance** of a route resolver. This instance should define which component should be used, and hardcode the route name to be passed into it. This instance will be used without any modifications by Flarum. +- The `resolverClass` key AND `component` key can be used to provide a **class** that will be used to instantiate a route resolver, to be used instead of Flarum's default one, as well as the component to use. Its constructor should take 2 arguments: `(component, routeName)`. +- The `component` key can be used alone to provide a component. This will result in the default behavior. + +For example: + +```js +// See above for a custom page example +import CustomPage from './components/CustomPage'; +// See below for a custom resolver example +import CustomPageResolver from './resolvers/CustomPageResolver'; + +// Use a route resolver instance +app.routes['resolverInstance'] = {path: '/custom/path/1', resolver: { + onmatch: function(args) { + if (!app.session.user) return m.route.SKIP; + + return CustomPage; + } +}}; + +// Use a custom route resolver class +app.routes['resolverClass'] = {path: '/custom/path/2', resolverClass: CustomPageResolver, component: CustomPage}; + +// Use the default resolver class (`flarum/common/resolvers/DefaultResolver`) +app.routes['resolverClass'] = {path: '/custom/path/2', component: CustomPage}; +``` + +### Custom Resolvers + +We strongly encourage custom route resolvers to extend `flarum/common/resolvers/DefaultResolver`. For example, Flarum's `flarum/forum/resolvers/DiscussionPageResolver` assigns the same key to all links to the same discussion (regardless of the current post), and triggers scrolling when using `m.route.set` to go from one post to another on the same discussion page: + +```js +import DefaultResolver from '../../common/resolvers/DefaultResolver'; + +/** + * This isn't exported as it is a temporary measure. + * A more robust system will be implemented alongside UTF-8 support in beta 15. + */ +function getDiscussionIdFromSlug(slug: string | undefined) { + if (!slug) return; + return slug.split('-')[0]; +} + +/** + * A custom route resolver for DiscussionPage that generates the same key to all posts + * on the same discussion. It triggers a scroll when going from one post to another + * in the same discussion. + */ +export default class DiscussionPageResolver extends DefaultResolver { + static scrollToPostNumber: number | null = null; + + makeKey() { + const params = { ...m.route.param() }; + if ('near' in params) { + delete params.near; + } + params.id = getDiscussionIdFromSlug(params.id); + return this.routeName.replace('.near', '') + JSON.stringify(params); + } + + onmatch(args, requestedPath, route) { + if (route.includes('/d/:id') && getDiscussionIdFromSlug(args.id) === getDiscussionIdFromSlug(m.route.param('id'))) { + DiscussionPageResolver.scrollToPostNumber = parseInt(args.near); + } + + return super.onmatch(args, requestedPath, route); + } + + render(vnode) { + if (DiscussionPageResolver.scrollToPostNumber !== null) { + const number = DiscussionPageResolver.scrollToPostNumber; + // Scroll after a timeout to avoid clashes with the render. + setTimeout(() => app.current.get('stream').goToNumber(number)); + DiscussionPageResolver.scrollToPostNumber = null; + } + + return super.render(vnode); + } +} +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md new file mode 100644 index 000000000..43b53dd66 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md @@ -0,0 +1,422 @@ +# Frontend Development + +This page describes how to make changes to Flarum's user interface. How to add buttons, marquees, and blinking text. 🤩 + +[Remember](/extend/start.md#architecture), Flarum's frontend is a **single-page JavaScript application**. There's no Twig, Blade, or any other kind of PHP template to speak of. The few templates that are present in the backend are only used to render search-engine-optimized content. All changes to the UI need to be made via JavaScript. + +Flarum has two separate frontend applications: + +* `forum`, the public side of your forum where users create discussions and posts. +* `admin`, the private side of your forum where, as an administrator of your forum, you configure your Flarum installation. + +They share the same foundational code, so once you know how to extend one, you know how to extend both. + +:::tip Schreiben! + +Along with new TypeScript support, we have a [`tsconfig` package](https://www.npmjs.com/package/flarum-tsconfig) available, which you should install as a dev dependency to gain access to our typings. Make sure you follow the instructions in the [package's README](https://github.com/flarum/flarum-tsconfig#readme) to configure typings support. + +::: + +## Transpilation and File Structure + +This portion of the guide will explain the necessary file setup for extensions. Once again, we highly recommend using the [Flarum CLI](https://github.com/flarum/cli) to set up the file structure for you. That being said, you should still read this to understand what's going on beneath the surface. + +Before we can write any JavaScript, we need to set up a **transpiler**. This allows us to use [TypeScript](https://www.typescriptlang.org/) and its magic in Flarum core and extensions. + +In order to do this transpilation, you need to be working in a capable environment. No, not the home/office kind of environment – you can work in the bathroom for all I care! I'm talking about the tools that are installed on your system. You'll need: + +* Node.js and npm ([Download](https://nodejs.org/en/download/)) +* Webpack (`npm install -g webpack`) + +This can be tricky because everyone's system is different. From the OS you're using, to the program versions you have installed, to the user access permissions – I get chills just thinking about it! If you run into trouble, ~~tell him I said hi~~ use [Google](https://google.com) to see if someone has encountered the same error as you and found a solution. If not, ask for help from the [Flarum Community](https://discuss.flarum.org) or on the [Discord chat](https://flarum.org/discord/). + +It's time to set up our little JavaScript transpilation project. Create a new folder in your extension called `js`, then pop in a couple of new files. A typical extension will have the following frontend structure: + +``` +js +├── dist (compiled js is placed here) +├── src +│ ├── admin +│ └── forum +├── admin.js +├── forum.js +├── package.json +├── tsconfig.json +└── webpack.config.js +``` + +### package.json + +```json +{ + "private": true, + "name": "@acme/flarum-hello-world", + "dependencies": { + "flarum-webpack-config": "^1.0.0", + "webpack": "^4.0.0", + "webpack-cli": "^4.0.0" + }, + "devDependencies": { + "flarum-tsconfig": "^1.0.0" + }, + "scripts": { + "dev": "webpack --mode development --watch", + "build": "webpack --mode production" + } +} +``` + +This is a standard JS [package-description file](https://docs.npmjs.com/files/package.json), used by npm and Yarn (Javascript package managers). You can use it to add commands, js dependencies, and package metadata. We're not actually publishing a npm package: this is simply used to collect dependencies. + +Please note that we do not need to include `flarum/core` or any flarum extensions as dependencies: they will be automatically packaged when Flarum compiles the frontends for all extensions. + +### webpack.config.js + +```js +const config = require('flarum-webpack-config'); + +module.exports = config(); +``` + +[Webpack](https://webpack.js.org/concepts/) is the system that actually compiles and bundles all the javascript (and its dependencies) for our extension. To work properly, our extensions should use the [official flarum webpack config](https://github.com/flarum/flarum-webpack-config) (shown in the above example). + +### tsconfig.json + +```json +{ + // Use Flarum's tsconfig as a starting point + "extends": "flarum-tsconfig", + // This will match all .ts, .tsx, .d.ts, .js, .jsx files in your `src` folder + // and also tells your Typescript server to read core's global typings for + // access to `dayjs` and `$` in the global namespace. + "include": ["src/**/*", "../vendor/flarum/core/js/dist-typings/@types/**/*"], + "compilerOptions": { + // This will output typings to `dist-typings` + "declarationDir": "./dist-typings", + "baseUrl": ".", + "paths": { + "flarum/*": ["../vendor/flarum/core/js/dist-typings/*"] + } + } +} +``` + +This is a standard configuration file to enable support for Typescript with the options that Flarum needs. + +Always ensure you're using the latest version of this file: https://github.com/flarum/flarum-tsconfig#readme. + +Even if you choose not to use TypeScript in your extension, which is supported natively by our Webpack config, it's still recommended to install the `flarum-tsconfig` package and to include this configuration file so that your IDE can infer types for our core JS. + +To get the typings working, you'll need to run `composer update` in your extension's folder to download the latest copy of Flarum's core into a new `vendor` folder. Remember not to commit this folder if you're using a version control system such as Git. + +You may also need to restart your IDE's TypeScript server. In Visual Studio Code, you can press F1, then type "Restart TypeScript Server" and hit ENTER. This might take a minute to complete. + +### admin.js and forum.js + +These files contain the root of our actual frontend JS. You could put your entire extension here, but that would not be well organized. For this reason, we recommend putting the actual source code in `src`, and having these files just export the contents of `src`. For instance: + +```js +// admin.js +export * from './src/admin'; + +// forum.js +export * from './src/forum'; +``` + +### src + +If following the recommendations for `admin.js` and `forum.js`, we'll want to have 2 subfolders here: one for `admin` frontend code, and one for `forum` frontend code. If you have components, models, utils, or other code that is shared across both frontends, you may want to create a `common` subfolder and place it there. + +Structure for `admin` and `forum` is identical, so we'll just show it for `forum` here: + +``` +src/forum/ +├── components/ +|-- models/ +├── utils/ +└── index.js +``` + +`components`, `models`, and `utils` are directories that contain files where you can define custom [components](#components), [models](models.md#frontend-models), and reusable util helper functions. Please note that this is all simply a recommendation: there's nothing forcing you to use this particular file structure (or any other file structure). + +The most important file here is `index.js`: everything else is just extracting classes and functions into their own files. Let's go over a typical `index.js` file structure: + +```js +import { extend, override } from 'flarum/common/extend'; + +// We provide our extension code in the form of an "initializer". +// This is a callback that will run after the core has booted. +app.initializers.add('acme-flarum-hello-world', function(app) { + // Your Extension Code Here + console.log("EXTENSION NAME is working!"); +}); +``` + +We'll go over tools available for extensions below. + +### Importing + +You should familiarize yourself with proper syntax for [importing js modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import), as most extensions larger than a few lines will split their js into multiple files. + +Pretty much every Flarum extension will need to import *something* from Flarum Core. Like most extensions, core's JS source code is split up into `admin`, `common`, and `forum` folders. You can import the file by prefixing its path in the Flarum core source code with `flarum`. So `admin/components/AdminLinkButton` is available as `flarum/admin/components/AdminLinkButton`, `common/Component` is available as `flarum/common/Component`, and `forum/states/PostStreamState` is available as `flarum/forum/states/PostStreamState`. + +In some cases, an extension may want to extend code from another flarum extension. This is only possible for extensions which explicitly export their contents. + +* `flarum/tags` and `flarum/flags` are currently the only bundled extensions that allow extending their JS. You can import their contents from `flarum/{EXT_NAME}/PATH` (e.g. `flarum/tags/components/TagHero`). +* The process for extending each community extension is different; you should consult documentation for each individual extension. + +### Transpilation + +OK, time to fire up the transpiler. Run the following commands in the `js` directory: + +```bash +npm install +npm run dev +``` + +This will compile your browser-ready JavaScript code into the `js/dist/forum.js` file, and keep watching for changes to the source files. Nifty! + +When you've finished developing your extension (or before a new release), you'll want to run `npm run build` instead of `npm run dev`: this builds the extension in production mode, which makes the source code smaller and faster. + +## Asset Registration + +### JavaScript + +In order for your extension's JavaScript to be loaded into the frontend, we need to tell Flarum where to find it. We can do this using the `Frontend` extender's `js` method. Add it to your extension's `extend.php` file: + +```php +js(__DIR__.'/js/dist/forum.js') +]; +``` + +Flarum will make anything you `export` from `forum.js` available in the global `flarum.extensions['acme-hello-world']` object. Thus, you may choose to expose your own public API for other extensions to interact with. + +:::tip Externe Bibliotheken + +Only one main JavaScript file per extension is permitted. If you need to include any external JavaScript libraries, either install them with NPM and `import` them so they are compiled into your JavaScript file, or see [Routes and Content](/extend/routes.md) to learn how to add extra `'; + }) +]; +``` + +You can also add content onto your frontend route registrations: + +```php +return [ + (new Extend\Frontend('forum')) + ->route('/users', 'acme.users', function (Document $document, Request $request) { + $document->title = 'Users'; + }) +]; +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/search.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/search.md new file mode 100644 index 000000000..167372780 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/search.md @@ -0,0 +1,202 @@ +# Searching and Filtering + +Flarum treats searching and filtering as parallel but distinct processes. Which process is used to handle a request to a [`List` API endpoint](/extend/api.md#api-endpoints) depends on the query parameters: + +- Filtering is applied when the `filter[q]` query param is omitted. Filters represent **structured** queries: for instance, you might want to only retrieve discussions in a certain category, or users who registered before a certain date. Filtering computes results based entirely on `filter[KEY] = VALUE` query parameters. +- Searching is applied when the `filter[q]` query param is included. Searches represent **unstructured** queries: the user submits an arbitrary string, and data records that "match" it are returned. For instance, you might want to search discussions based on the content of their posts, or users based on their username. Searching computes results based solely on parsing the `filter[q]` query param: all other `filter[KEY] = VALUE` params are ignored when searching. It's important to note that searches aren't entirely unstructured: the dataset being searched can be constrained by gambits (which are very similar to filters, and will be explained later). + +This distinction is important because searches and filters have very different use cases: filters represent *browsing*: that is, the user is passively looking through some category of content. In contrast, searches represent, well, *searching*: the user is actively looking for content based on some criteria. + +Flarum implements searching and filtering via per-model `Searcher` and `Filterer` classes (discussed in more detail below). Both classes accept a [`Flarum\Query\QueryCriteria`](https://api.docs.flarum.org/php/master/flarum/query/querycriteria) instance (a wrapper around the user and query params), and return a [`Flarum\Query\QueryResults`](https://api.docs.flarum.org/php/master/flarum/query/queryresults) instance (a wrapper around an Eloquent model collection). This common interface means that adding search/filter support to models is quite easy. + +One key advantage of this split is that it allows searching to be implemented via an external service, such as ElasticSearch. For larger communities, this can be significantly more performant and accurate. There isn't a dedicated extender for this yet, so for now, replacing the default Flarum search driver requires overriding the container bindings of `Searcher` classes. This is a highly advanced use case; if you're interested in doing this, please reach out on our [community forums](https://discuss.flarum.org/). + +Remember that the [JSON:API schema](https://jsonapi.org/format) is used for all API requests. + +:::tip Code wiederverwenden + +Often, you might want to use the same class as both a `Filter` and a `Gambit` (both explained below). Your classes can implement both interface; see Flarum core's [`UnreadFilterGambit`](https://github.com/flarum/framework/blob/main/framework/core/src/Discussion/Query/UnreadFilterGambit.php) for an example. + +::: + +:::tip Query Builder vs. Eloquent Builder + +`Filter`s, `Gambit`s, filter mutators, and gambit mutators (all explained below) receive a "state" parameter, which wraps + +::: + +## Filtering + +Filtering constrains queries based on `Filters` (highlighted in code to avoid confusion with the process of filtering), which are classes that implement `Flarum\Filter\FilterInterface` and run depending on query parameters. After filtering is complete, a set of callbacks called "filter mutators" run for every filter request. + +When the `filter` method on a `Filterer` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Filter/AbstractFilterer.php#L50-L93)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Filterer` class's `getQuery()` method. +2. We loop through all `filter[KEY] = VALUE` query params. For each of these, any `Filter`s registered to the model whose `getFilterKey()` method matches the query param `KEY` is applied. `Filter`s can be negated by providing the query param as `filter[-KEY] = VALUE`. Whether or not a `Filter` is negated is passed to it as an argument: implementing negation is up to the `Filter`s. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "filter mutators" are applied. These are callbacks that receive the filter state (a wrapper around the query builder and current user) and filter criteria, and perform some arbitrary changes. All "filter mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Filtering for an Existing Model + +Let's say you've added a `country` column to the User model, and would like to filter users by country. We'll need to define a custom `Filter`: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +Note that `FilterState` is a wrapper around the Eloquent builder's underlying Query builder and the current user. + +Also, let's pretend that for some reason, we want to omit any users that have a different country from the current user on ANY filter. We can use a "filter mutator" for this: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +Now, all we need to do is register these via the Filter extender: + +```php + // Other extenders + (new Extend\Filter(UserFilterer::class)) + ->addFilter(CountryFilter::class) + ->addFilterMutator(OnlySameCountryFilterMutator::class), + // Other extenders +``` + +### Add Filtering to a New Model + +To filter a model that doesn't support filtering, you'll need to create a subclass of `Flarum/Filter/AbstractFilterer` for that model. For an example, see core's [UserFilterer](https://github.com/flarum/framework/blob/main/framework/core/src/User/Filter/UserFilterer.php). + +Then, you'll need to use that filterer in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +## Searching + +Searching constrains queries by applying `Gambit`s, which are classes that implement `Flarum\Search\GambitInterface`, based on the `filter[q]` query param. After searching is complete, a set of callbacks called "search mutators" run for every search request. + +When the `search` method on a `Searcher` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Search/AbstractSearcher.php#L55-L79)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Searcher` class's `getQuery()` method. +2. The `filter[q]` param is split by spaces into "tokens". Each token is matched against the model's registered `Gambit`s (each gambit has a `match` method). For any tokens that match a gambit, that gambit is applied, and the token is removed from the query string. Once all regular `Gambit`s have ran, all remaining unmatched tokens are passed to the model's `FullTextGambit`, which implements the actual searching logic. For example if searching discussions, in the `filter[q]` string `'author:1 hello is:hidden' world`, `author:1` and `is:hidden` would get matched by core's Author and Hidden gambits, and `'hello world'` (the remaining tokens) would be passed to the `DiscussionFulltextGambit`. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "search mutators" are applied. These are callbacks that receive the search state (a wrapper around the query builder and current user) and criteria, and perform some arbitrary changes. All "search mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Searching for an Existing Model + +Let's reuse the "country" examples we used above, and see how we'd implement the same things for searching: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +:::warning Keine Leerzeichen in Gambit-Mustern! + +Flarum splits the `filter[q]` string into tokens by splitting it at spaces. This means that your custom gambits can NOT use spaces as part of their pattern. + +::: + +:::tip AbstractRegexGambit + +All a gambit needs to do is implement `Flarum\Search\GambitInterface`, which receives the search state and a token. It should return if this gambit applies for the given token, and if so, make whatever mutations are necessary to the query builder accessible as `$searchState->getQuery()`. + +However, for most gambits, the `AbstractRegexGambit` abstract class (used above) should be used as a base class. This makes it a lot simpler to match and apply gambits. + +::: + +Similarly, the search mutator we need is almost identical to the filter mutator from before: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +We can register these via the `SimpleFlarumSearch` extender (in the future, the `Search` extender will be used for registering custom search drivers): + +```php + // Other extenders + (new Extend\SimpleFlarumSearch(UserSearcher::class)) + ->addGambit(CountryGambit::class) + ->addSearchMutator(OnlySameCountrySearchMutator::class), + // Other extenders +``` + +### Add Searching to a New Model + +To support searching for a model, you'll need to create a subclass of `Flarum/Search/AbstractSearcher` for that model. For an example, see core's [UserSearcher](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/UserSearcher.php). + +Then, you'll need to use that searcher in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +Every searcher **must** have a fulltext gambit (the logic that actually does the searching). Otherwise, it won't be booted by Flarum, and you'll get an error. See core's [FulltextGambit for users](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/Gambit/FulltextGambit.php) for an example. You can set (or override) the full text gambit for a searcher via the `SimpleFlarumSearch` extender's `setFullTextGambit()` method. + +### Search Drivers + +Coming soon! + +## Frontend Tools + +Coming soon! diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md new file mode 100644 index 000000000..65d98e0bf --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md @@ -0,0 +1,65 @@ +# Service Provider + +As noted throughout this documentation, Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection. [Service Providers](https://laravel.com/docs/8.x/providers) allow low-level configuration and modification of the Flarum backend. The most common use case for service providers is to create, modify, or replace container bindings. That being said, service providers allow you full access to run whatever logic you need during application boot with access to the container. + +:::caution Nur für Fortgeschrittene!!! + +Unlike with other extenders, the Service Provider layer is NOT use-case driven, and is NOT considered public API. It is subject to change at any time, without notice or deprecation. This should only be used if you know what you're doing, and the other extenders don't satisfy your use case. + +::: + +## Flarum Boot Process + +To understand service providers, you must first understand the order in which Flarum boots. Most of this happens in [Flarum\Foundation\InstalledSite](https://github.com/flarum/framework/blob/main/framework/core/src/Foundation/InstalledSite.php) + +1. The container and application are initialized, and essential bindings (config, environment, logger) are registered +2. The `register` methods of all core service providers are run. +3. The `extend` methods of all extenders used by all enabled extensions are run. +4. The `extend` methods of all extenders used in the Flarum site's local `extend.php` are run. +5. The `boot` methods of all core service providers are run. + +## Custom Service Providers + +A custom service provider should extend `Flarum\Foundation\AbstractServiceProvider`, and can have a `boot` and a `register` method. For example: + +```php +container->resolving(SomeClass::class, function ($container) { + return new SomeClass($container->make('some.binding')); + }); + } + + public function boot(Container $container) + { + // custom logic here + } +} +``` + +The `register` method will run during step (3) above, and the `boot` method will run during step (5) above. In the `register` method, the container is available via `$this->container`. In the `boot` method, the container (or any other arguments), should be injected via typehinted method arguments. + +Flarum does not currently support Laravel Octane, but some [best practices](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane), like using the `$container` argument inside `bind`, `singleton`, and `resolving` callbacks instead of `$this->container` should be used. See the [Octane documentation](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane) for more information. + +To actually register your custom service provider, you can use the `ServiceProvider` extender in `extend.php`: + +```php +register(CustomServiceProvider::class), + // Other extenders +]; +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/settings.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/settings.md new file mode 100644 index 000000000..ffefdcde5 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/settings.md @@ -0,0 +1,90 @@ +# Settings + +At some point while making an extension, you might want to read some of the forum's settings or store certain settings specific to your extension. Thankfully, Flarum makes this very easy. + +## The Settings Repository + +Reading or changing settings can be done using an implementation of the `SettingsRepositoryInterface`. Because Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection, you don't need to worry about where to obtain such a repository, or how to instantiate one. Instead, you can rely on the container to instantiate your class and inject the correct dependencies. + +```php +settings = $settings; + } +} +``` + +Great! Now the `SettingsRepositoryInterface` is available through `$this->settings` to our class. + +### Reading Settings + +To read settings, all we have to do is use the repository's `get()` function: + +`$this->settings->get('forum_title')` + +The `get()` function accepts two arguments: + +1. The name of the setting you are trying to read. +2. (Optional) A default value if no value has been stored for such a setting. By default, this will be `null`. + +### Storing Settings + +Storing settings ist just as easy, use the `set()` function: + +`$this->settings->set('forum_title', 'Super Awesome Forum')` + +The `set` function also accepts two arguments: + +1. The name of the setting you are trying to change. +2. The value you want to store for this setting. + +### Other Functions + +The `all()` function returns an array of all known settings. + +The `delete($name)` function lets you remove a named setting. + +## Settings in the Frontend + +### Editing Settings + +To learn more about adding settings through the admin dashboard, see the [relevant documentation](admin.md). +### Accessing Settings + +All settings are available in the `admin` frontend via the `app.data.settings` global. However, this is not done in the `forum` frontend, as anyone can access it, and you wouldn't want to leak all your settings! (Seriously, that could be a very problematic data breach). + +Instead, if we want to use settings in the `forum` frontend, we'll need to serialize them and send them alongside the initial forum data payload. + +This can be done via the `Settings` extender. For example: + +**extend.php** + +```php +use Flarum\Extend; + +return [ + (new Extend\Settings) + ->serializeToForum('myCoolSetting', 'my.cool.setting.key') + ->serializeToForum('myCoolSettingModified', 'my.cool.setting.key', function ($retrievedValue) { + // This third argument is optional, and allows us to pass the retrieved setting through some custom logic. + // In this example, we'll append a string to it. + + return "My Cool Setting: $retrievedValue"; + }, "default value!"), +] +``` + +Now, the `my.cool.setting.key` setting will be accessible in the frontend as `app.forum.attribute("myCoolSetting")`, and our modified value will be accessible via `app.forum.attribute("myCoolSettingModified")`. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md new file mode 100644 index 000000000..3dc39416b --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md @@ -0,0 +1 @@ +# Model Slugging diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/start.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/start.md new file mode 100644 index 000000000..b73125a7c --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/start.md @@ -0,0 +1,153 @@ +# Getting Started + +Want to build a Flarum extension? You've come to the right place! This document will take you through some essential concepts, after which you'll build your first Flarum extension from scratch. + +## Architecture + +In order to understand how to extend Flarum, first we need to understand a bit about how Flarum is built. + +Be aware that Flarum uses some _modern_ languages and tools. If you've only ever built WordPress plugins before, you might feel a bit out of your depth! That's OK — this is a great time to learn cool new things and extend your skillset. However, we would advise that you become somewhat familiar with the technologies described below before proceeding. + +Flarum is made up of three layers: + +* First, there is the **backend**. This is written in [object-oriented PHP](https://laracasts.com/series/object-oriented-bootcamp-in-php), and makes use of a wide array of [Laravel](https://laravel.com/) components and other packages via [Composer](https://getcomposer.org/). You'll also want to familiarize yourself with the concept of [Dependency Injection](https://laravel.com/docs/8.x/container), which is used throughout our backend. + +* Second, the backend exposes a **public API** which allows frontend clients to interface with your forum's data. This is built according to the [JSON:API specification](https://jsonapi.org/). + +* Finally, there is the default web interface which we call the **frontend**. This is a [single-page application](https://en.wikipedia.org/wiki/Single-page_application) which consumes the API. It's built with a simple React-like framework called [Mithril.js](https://mithril.js.org). + +Extensions will often need to interact with all three of these layers to make things happen. For example, if you wanted to build an extension that adds custom fields to user profiles, you would need to add the appropriate database structures in the **backend**, expose that data in the **public API**, and then display it and allow users to edit it on the **frontend**. + +So... how do we extend these layers? + +## Extenders + +In order to extend Flarum, we will be using a concept called **extenders**. Extenders are *declarative* objects that describe in plain terms the goals you are trying to achieve (such as adding a new route to your forum, or executing some code when a new discussion was created). + +Every extender is different. However, they will always look somewhat similar to this: + +```php +// Register a JavaScript and a CSS file to be delivered with the forum frontend +(new Extend\Frontend('forum')) + ->js(__DIR__.'/forum-scripts.js') + ->css(__DIR__.'/forum-styles.css') +``` + +You first create an instance of the extender, and then call methods on it for further configuration. All of these methods return the extender itself, so that you can achieve your entire configuration just by chaining method calls. + +To keep things consistent, we use this concept of extenders in both the backend (in PHP land) and the frontend (in JavaScript land). _Everything_ you do in your extension should be done via extenders, because they are a **guarantee** we are giving to you that a future minor release of Flarum won't break your extension. + +All of the extenders currently available to you from Flarum's core can be found in the [`Extend` namespace](https://github.com/flarum/framework/blob/main/framework/core/src/Extend) [(PHP API documentation)](https://api.docs.flarum.org/php/master/flarum/extend) Extensions may also offer their [own extenders](extensibility.md#custom-extenders). + +## Hello World + +Want to see an extender in action? The `extend.php` file in the root of your Flarum installation is the easiest way to register extenders just for your site. It should return an array of extender objects. Pop it open and add the following: + +```php +content(function (Document $document) { + $document->head[] = ''; + }) +]; +``` + +Now pay your forum a visit for a pleasant (albeit extremely obtrusive) greeting. 👋 + +For simple site-specific customizations – like adding a bit of custom CSS/JavaScript, or integrating with your site's authentication system – the `extend.php` file in your forum's root is great. But at some point, your customization might outgrow it. Or maybe you have wanted to build an extension to share with the community from the get-go. Time to build an extension! + +## Extension Packaging + +[Composer](https://getcomposer.org) is a dependency manager for PHP. It allows applications to easily pull in external code libraries and makes it easy to keep them up-to-date so that security and bug fixes are propagated rapidly. + +As it turns out, every Flarum extension is also a Composer package. That means someone's Flarum installation can "require" a certain extension and Composer will pull it in and keep it up-to-date. Nice! + +During development, you can work on your extensions locally and set up a [Composer path repository](https://getcomposer.org/doc/05-repositories.md#path) to install your local copy. Create a new `packages` folder in the root of your Flarum installation, and then run this command to tell Composer that it can find packages in here: + +```bash +composer config repositories.0 path "packages/*" +``` + +Now let's start building our first extension. Make a new folder inside `packages` for your extension called `hello-world`. We'll put two files in it: `extend.php` and `composer.json`. These files serve as the heart and soul of the extension. + +### extend.php + +The `extend.php` file is just like the one in the root of your site. It will return an array of extender objects that tell Flarum what you want to do. For now, just move over the `Frontend` extender that you had earlier. + +### composer.json + +We need to tell Composer a bit about our package, and we can do this by creating a `composer.json` file: + +```json +{ + "name": "acme/flarum-hello-world", + "description": "Say hello to the world!", + "type": "flarum-extension", + "require": { + "flarum/core": "^1.0.0" + }, + "autoload": { + "psr-4": {"Acme\\HelloWorld\\": "src/"} + }, + "extra": { + "flarum-extension": { + "title": "Hello World", + "icon": { + "name": "fas fa-smile", + "backgroundColor": "#238c59", + "color": "#fff" + } + } + } +} +``` + +* **name** is the name of the Composer package in the format `vendor/package`. + * You should choose a vendor name that’s unique to you — your GitHub username, for example. For the purposes of this tutorial, we’ll assume you’re using `acme` as your vendor name. + * You should prefix the `package` part with `flarum-` to indicate that it’s a package specifically intended for use with Flarum. + +* **description** is a short one-sentence description of what the extension does. + +* **type** MUST be set to `flarum-extension`. This ensures that when someone "requires" your extension, it will be identified as such. + +* **require** contains a list of your extension's own dependencies. + * You'll want to specify the version of Flarum that your extension is compatible with here. + * This is also the place to list other Composer libraries your code needs to work. + +* **autoload** tells Composer where to find your extension's classes. The namespace in here should reflect your extensions' vendor and package name in CamelCase. + +* **extra.flarum-extension** contains some Flarum-specific information, like your extension's display name and how its icon should look. + * **title** is the display name of your extension. + * **icon** is an object which defines your extension's icon. The **name** property is a [Font Awesome icon class name](https://fontawesome.com/icons). All other properties are used as the `style` attribute for your extension's icon. + +See [the composer.json schema](https://getcomposer.org/doc/04-schema.md) documentation for information about other properties you can add to `composer.json`. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +Use the CLI to automatically create your extension's scaffolding: +```bash +$ flarum-cli init +``` + +::: + +### Installing Your Extension + +The final thing we need to do to get up and running is to install your extension. Navigate to the root directory of your Flarum install and run the following command: + +```bash +composer require acme/flarum-hello-world *@dev +``` + +Once that's done, go ahead and fire 'er up on your forum's Administration page, then navigate back to your forum. + +*whizzing, whirring, metal clunking* + +Woop! Hello to you too, extension! + +We're making good progress. We've learned how to set up our extension and use extenders, which opens up a lot of doors. Read on to learn how to extend Flarum's frontend. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md new file mode 100644 index 000000000..28e6c4aa7 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md @@ -0,0 +1,86 @@ +# Static Code Analysis + +Static code analysis is the process of analyzing the source code against a set of rules to find bugs, code smells, and security vulnerabilities. This is a great way to improve the quality of your code and to find potential issues before they are deployed to production. An example is validating the typings of a function to ensure that the function is called with the correct arguments. + +Flarum provides a static code analysis package based on [PHPStan](https://phpstan.org/) that can be added to your extension. In this guide, we will show you how to add the package to your extension and how to run the analysis. + +## Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update the infrastructure for phpstan to your code: + +```bash +$ flarum-cli infra phpstan +``` + +::: + +First you need to require the `flarum/phpstan` package in your extension. You can do this by running the following command in the root of our extension: + +```bash +composer require --dev flarum/phpstan:^1.0 +``` + +Next, you need to create a `phpstan.neon` file in the root of your extension. This file contains [the configuration for PHPStan](https://phpstan.org/config-reference). You can copy the following configuration into the file: + +```neon +includes: + - vendor/flarum/phpstan/extension.neon + +parameters: + # The level will be increased in Flarum 2.0 + level: 5 + paths: + - src + - extend.php + excludePaths: + - *.blade.php + checkMissingIterableValueType: false + databaseMigrationsPath: ['migrations'] +``` + +Finally, you need to add the following script to your `composer.json` file: + +```json +{ + "scripts": { + "analyse:phpstan": "phpstan analyse", + "clear-cache:phpstan": "phpstan clear-result-cache" + }, + "scripts-descriptions": { + "analyse:phpstan": "Run static analysis" + } +} +``` + +## Running the analysis + +To run the analysis, you can run the following command in the root of your extension: + +```bash +composer analyse:phpstan +``` + +If you want to clear the cache before running the analysis, you can run the following command: + +```bash +composer clear-cache:phpstan && composer analyse:phpstan +``` + +## GitHub Actions + +You can also run the analysis using GitHub Actions. Checkout the page on [GitHub Actions](github-actions.md) for more information. + +## Tips + +### Extended model attribute types + +PHPStan needs to be able to determine the type of an attribute added to an existing model. To do this you can use the `Extend\Model(...)->cast(...)` method. + +For example, if your extension were to add a `is_cool` attribute to the `User` model, you can use [attribute casting](https://laravel.com/docs/8.x/eloquent-mutators#attribute-casting) to explicitly define the attribute as boolean. The `flarum/phpstan` package will automatically detect this and communicate it to PHPStan. + +```php +(new Extend\Model(User::class)) + ->cast('is_cool', 'bool'), +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/testing.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/testing.md new file mode 100644 index 000000000..2607b03da --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/testing.md @@ -0,0 +1,565 @@ +# Testing + +Automated testing ensures that your extension performs as you expect it to, helps avoid introducing new bugs or regressions, and saves time on manual testing. Flarum currently provides tooling for automated backend unit and integration tests, and we plan to release support for frontend unit testing and E2E testing in the future. + +## Backend Tests + +The `flarum/testing` library is used by core and some bundled extensions for automated unit and integration tests. It is essentially a collection of utils that allow testing Flarum core and extensions with PHPUnit. + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update backend testing infrastructure to your code: + +```bash +$ flarum-cli infra backendTesting +``` + +::: + +```bash +composer require --dev flarum/testing:^1.0 +``` + +Then, you will need to set up a file structure for tests, and add PHPUnit configuration: + +``` +tests +├── fixtures (put any files needed by your tests here (blade templates, images, etc)) +├── integration +│ ├── setup.php (code below) +│ └── PUT INTEGRATION TESTS HERE (organizing into folder is generally a good idea) +├── unit +│ ├── PUT UNIT TESTS HERE +├── phpunit.integration.xml (code below) +└── phpunit.unit.xml (code below) +``` + +#### phpunit.integration.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for integration tests. You can tweak this as needed, but keep `backupGlobals`, `backupStaticAttributes`, and `processIsolation` unchanged. + +```xml + + + + + + + ./integration + + + +``` + +#### phpunit.unit.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for unit tests. You can tweak this as needed. + +```xml + + + + + + + ./unit + + + + + + +``` + +#### setup.php + +This script will be run to set up a testing database / file structure. + +```php +run(); +``` + +#### composer.json Modifications + +We will also want to add scripts to our `composer.json`, so that we can run our test suite via `composer test`. Add some variant of the following to your `composer.json`: + +```json +"scripts": { + "test": [ + "@test:unit", + "@test:integration" + ], + "test:unit": "phpunit -c tests/phpunit.unit.xml", + "test:integration": "phpunit -c tests/phpunit.integration.xml", + "test:setup": "@php tests/integration/setup.php" +}, +"scripts-descriptions": { + "test": "Runs all tests.", + "test:unit": "Runs all unit tests.", + "test:integration": "Runs all integration tests.", + "test:setup": "Sets up a database for use with integration tests. Execute this only once." +} +``` + +#### GitHub Testing Workflow + +To run tests on every commit and pull request, check out the [GitHub Actions](github-actions.md) page. + +--- + +Now that we have everything in place, we need to set up our testing site for integration tests. For this, we will need a MySQL or MariaDb instance, and a place to store testing files. + +Testing database information is configured via the `DB_HOST` (defaults to `localhost`), `DB_PORT` (defaults to `3306`), `DB_DATABASE` (defaults to `flarum_test`), `DB_USERNAME` (defaults to `root`), `DB_PASSWORD` (defaults to `root`), and `DB_PREFIX` (defaults to `''`) environmental variables. The testing tmp directory path is configured via the `FLARUM_TEST_TMP_DIR_LOCAL` or `FLARUM_TEST_TMP_DIR` environmental variables, with the former taking precedence over the latter. If neither are provided, a `tmp` directory will be created in the `vendor` folder of your extension's local install. + +Now that we've provided the needed information, all we need to do is run `composer test:setup` in our extension's root directory, and we have our testing environment ready to go! + +Since [(almost)](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/tests/integration/api/discussions/ListWithFulltextSearchTest.php#L29-L45) all database operations in integration tests are run in transactions, developers working on multiple extensions will generally find it more convenient to use one shared database and tmp directory for testing all their extensions. To do this, set the database config and `FLARUM_TEST_TMP_DIR` environmental variables in your `.bashrc` or `.bash_profile` to the path you want to use, and run the setup script for any one extension (you'll still want to include the setup file in every repo for CI testing via GitHub Actions). You should then be good to go for any Flarum extension (or core). + +### Using Integration Tests + +Flarum's integration test utils are contained in the `Flarum\Testing\integration\TestCase` class. It: + +- Boots (and makes available) an instance of the Flarum application. +- Allows pre-populating the database, enabling extensions, and adding extenders. +- Runs all database changes in transactions, so your test database retains the default post-installation state. +- Allows sending requests through the middleware stack to test HTTP endpoints. + +Your testcase classes should extend this class. + +#### Test Case Setup + +There are several important utilities available for your test cases: + +- The `setting($key, $value)` method allows you to override settings before the app has booted. This is useful if your boot process has logic depending on settings (e.g. which driver to use for some system). +- Similarly, the `config($key, $value)` method allows you to override config.php values before the app has booted. You can use dot-delimited keys to set deep-nested values in the config array. +- The `extension($extensionId)` method will take Flarum IDs of extensions to enable as arguments. Your extension should always call this with your extension's ID at the start of test cases, unless the goal of the test case in question is to confirm some behavior present without your extension, and compare that to behavior when your extension is enabled. If your extension is dependent on other extensions, make sure they are included in the composer.json `require` field (or `require-dev` for [optional dependencies](extending-extensions.md)), and also list their composer package names when calling `extension()`. Note that you must list them in a valid order. +- The `extend($extender)` method takes instances of extenders as arguments, and is useful for testing extenders introduced by your extension for other extensions to use. +- The `prepareDatabase()` method allow you to pre-populate your database. This could include adding users, discussions, posts, configuring permissions, etc. Its argument is an associative array that maps table names to arrays of [record arrays](https://laravel.com/docs/8.x/queries#insert-statements). + +If your test case needs users beyond the default admin user, you can use the `$this->normalUser()` method of the `Flarum\Testing\integration\RetrievesAuthorizedUsers` trait. + +:::warning + +The `TestCase` class will boot a Flarum instance the first time its `app()` method is called. Any uses of `prepareDatabase`, `extend`, or `extension` after this happens will have no effect. Make sure you have done all the setup you need in your test case before calling `app()`, or `database()`, `server()`, or `send()`, which call `app()` implicitly. If you need to make database modifications after the app has booted, you can use the regular Eloquent save method, or the `Illuminate\Database\ConnectionInterface` instance obtained via calling the `database()` method. + +::: + +Of course, since this is all based on PHPUnit, you can use the `setUp()` methods of your test classes for common setup tasks. + +For example: + +```php +setting('my.custom.setting', true); + + // Let's assume our extension depends on tags. + // Note that tags will need to be in your extension's composer.json's `require-dev`. + // Also, make sure you include the ID of the extension currently being tested, unless you're + // testing the baseline without your extension. + $this->extension('flarum-tags', 'my-cool-extension'); + + // Note that this input isn't validated: make sure you're populating with valid, representative data. + $this->prepareDatabase([ + 'users' => [ + $this->normalUser() // Available for convenience. + ], + 'discussions' => [ + ['id' => 1, 'title' => 'some title', 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 1, 'first_post_id' => 1, 'comment_count' => 1] + ], + 'posts' => [ + ['id' => 1, 'number' => 1, 'discussion_id' => 1, 'created_at' => Carbon::now(), 'user_id' => 1, 'type' => 'comment', 'content' => '

something

'] + ] + ]); + + // Most test cases won't need to test extenders, but if you want to, you can. + $this->extend((new CoolExtensionExtender)->doSomething('hello world')); + } + + /** + * @test + */ + public function some_phpunit_test_case() + { + // ... + } + + // ... +} +``` + +#### Sending Requests + +A common application of automated testing is pinging various HTTP endpoints with various data, authenticated as different users. You can use this to ensure that: + +- Users can't access content they're not supported to access. +- Permission-based create/edit/delete operations perform as expected. +- The type and schema of data returned is correct. +- Some desired side effect is applied when pinging an API. +- The basic API operations needed by your extension aren't erroring, and don't break when you make changes. + +`TestCase` provides several utilities: + +- The `request()` method constructs a `Psr\Http\Message\ServerRequestInterface` implementing object from a path, a method, and some options, which can be used for authentication, attaching cookies, or configuring the JSON request body. See the [method docblock](https://github.com/flarum/testing/blob/main/src/integration/TestCase.php) for more information on available options. +- Once you've created a request instance, you can send it (and get a response object back) via the `send()` method. + +For example: + +```php +send( + $this->request('GET', '/api/users', ['authenticatedAs' => 1]) + ->withQueryParams(['filter' => ['q' => 'john group:1'], 'sort' => 'username']) + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + /** + * @test + */ + public function can_create_user() + { + $response = $this->send( + $this->request( + 'POST', + '/api/users', + [ + 'authenticatedAs' => 1, + 'json' => [ + 'data' => [ + 'attributes' => [ + 'username' => 'test', + 'password' => 'too-obscure', + 'email' => 'test@machine.local' + ] + ] + ] + ] + ) + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + // ... +} +``` + +:::caution + +If you want to send query parameters in a GET request, you can't include them in the path; you'll need to add them afterwards with the `withQueryParams` method. + +::: + +:::caution + +This is an extreme edge case, but note that MySQL does not update the fulltext index in transactions, so the standard approach won't work if you're trying to test a modified fulltext query. See [core's approach](https://github.com/flarum/framework/blob/main/framework/core/tests/integration/extenders/SimpleFlarumSearchTest.php) for an example of a workaround. + +::: + +#### Console Tests + +If you want to test custom console commands, you can extend `Flarum\Testing\integration\ConsoleTestCase` (which itself extends the regular `Flarum\Testing\integration\TestCase`). It provides 2 useful methods: + +- `$this->console()` returns an instance of `Symfony\Component\Console\Application` +- `$this->runCommand()` takes an array that will be wrapped in `Symfony\Component\Console\Input\ArrayInput`, and run. See the [Symfony code docblock](https://github.com/symfony/console/blob/5.x/Input/ArrayInput.php#L22) for more information. + +For example: + +```php + 'some:command', // The command name, equivalent of `php flarum some:command` + 'foo' => 'bar', // arguments + '--lorem' => 'ipsum' // options + ]; + + $this->assertEquals('Some Output.', $this->runCommand($input)); + } +} +``` + +### Using Unit Tests + +Unit testing in Flarum uses [PHPUnit](https://phpunit.de/getting-started/phpunit-9.html) and so unit testing in flarum is much like any other PHP application. You can find [general tutorials on testing](https://www.youtube.com/watch?v=9-X_b_fxmRM) if you're also new to php. + +When writing unit tests in Flarum, here are some helpful tips. + +#### Mocking Flarum Services + +Unlike the running app, or even integration tests, there is no app/container/etc to inject service instances into our classes. Now all the useful settings, or helpers your extension use require a _mock_ . We want to limit mocking to just the key services, supporting only the minimum interactions needed to test the contract of our individual functions. + +```php + public function setUp(): void + { + parent::setUp(); + // example - if our setting needs settings, we can mock the settings repository + $settingsRepo = m::mock(SettingsRepositoryInterface::class); + // and then control specific return values for each setting key + $settingsRepo->shouldReceive('get')->with('some-plugin-key')->andReturn('some-value-useful-for-testing'); + // construct your class under test, passing mocked services as needed + $this->serializer = new YourClassUnderTest($settingsRepo); + } +``` + +Some aspects require more mocks. If you're validating authorization interactions for instance you might need to mock your users `User::class` and the request's method that provides them as well! + +``` + $this->actor = m::mock(User::class); + $request = m::mock(Request::class)->makePartial(); + $request->shouldReceive('getAttribute->getActor')->andReturn($this->actor); + $this->actor->shouldReceive('SOME PERMISSION')->andReturn(true/false); +``` + +NOTE: If you find your extension needs _lots and lots_ of mocks, or mocks that feel unrelated, it might be an opportunity to simplify your code, perhaps moving key logic into their own smaller functions (that dont require mocks). + +## Frontend Tests + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update frontend testing infrastructure to your code: + +```bash +$ flarum-cli infra frontendTesting +``` + +::: + +First, you need to install the Jest config dev dependency: + +```bash +$ yarn add --dev @flarum/jest-config +``` + +Then, add the following to your `package.json`: + +```json +{ + "type": "module", + "scripts": { + ..., + "test": "yarn node --experimental-vm-modules $(yarn bin jest)" + } +} +``` + +Rename `webpack.config.js` to `webpack.config.cjs`. This is necessary because Jest doesn't support ESM yet. + +Create a `jest.config.cjs` file in the root of your extension: + +```js +module.exports = require('@flarum/jest-config')(); +``` + +If you are using TypeScript, create tsconfig.test.json with the following content: + +```json +{ + "extends": "./tsconfig.json", + "include": ["tests/**/*"], + "files": ["../../../node_modules/@flarum/jest-config/shims.d.ts"] +} +``` + +Then, you will need to set up a file structure for tests: + +``` +js +├── dist +├── src +├── tests +│ ├── unit +│ │ └── functionTest.test.js +│ ├── integration +│ │ └── componentTest.test.js +├── package.json +├── tsconfig.json +├── tsconfig.test.json +├── jest.config.cjs +└── webpack.config.cjs +``` + +#### GitHub Testing Workflow + +To run tests on every commit and pull request, check out the [GitHub Actions](github-actions.md) page. + +### Using Unit Tests + +Like any other JS project, you can use Jest to write unit tests for your frontend code. Checkout the [Jest docs](https://jestjs.io/docs/using-matchers) for more information on how to write tests. + +Here's a simple example of a unit test fo core's `abbreviateNumber` function: + +```ts +import abbreviateNumber from '../../../../src/common/utils/abbreviateNumber'; + +test('does not change small numbers', () => { + expect(abbreviateNumber(1)).toBe('1'); +}); + +test('abbreviates large numbers', () => { + expect(abbreviateNumber(1000000)).toBe('1M'); + expect(abbreviateNumber(100500)).toBe('100.5K'); +}); + +test('abbreviates large numbers with decimal places', () => { + expect(abbreviateNumber(100500)).toBe('100.5K'); + expect(abbreviateNumber(13234)).toBe('13.2K'); +}); +``` + +### Using Integration Tests + +Integration tests are used to test the components of your frontend code and the interaction between different components. For example, you might test that a page component renders the correct content based on certain parameters. + +Here's a simple example of an integration test for core's `Alert` component: + +```ts +import Alert from '../../../../src/common/components/Alert'; +import m from 'mithril'; +import mq from 'mithril-query'; +import { jest } from '@jest/globals'; + +describe('Alert displays as expected', () => { + it('should display alert messages with an icon', () => { + const alert = mq(m(Alert, { type: 'error' }, 'Shoot!')); + expect(alert).toContainRaw('Shoot!'); + expect(alert).toHaveElement('i.icon'); + }); + + it('should display alert messages with a custom icon when using a title', () => { + const alert = mq(Alert, { type: 'error', icon: 'fas fa-users', title: 'Woops..' }); + expect(alert).toContainRaw('Woops..'); + expect(alert).toHaveElement('i.fas.fa-users'); + }); + + it('should display alert messages with a title', () => { + const alert = mq(m(Alert, { type: 'error', title: 'Error Title' }, 'Shoot!')); + expect(alert).toContainRaw('Shoot!'); + expect(alert).toContainRaw('Error Title'); + expect(alert).toHaveElement('.Alert-title'); + }); + + it('should display alert messages with custom controls', () => { + const alert = mq(Alert, { type: 'error', controls: [m('button', { className: 'Button--test' }, 'Click me!')] }); + expect(alert).toHaveElement('button.Button--test'); + }); +}); + +describe('Alert is dismissible', () => { + it('should show dismiss button', function () { + const alert = mq(m(Alert, { dismissible: true }, 'Shoot!')); + expect(alert).toHaveElement('button.Alert-dismiss'); + }); + + it('should call ondismiss when dismiss button is clicked', function () { + const ondismiss = jest.fn(); + const alert = mq(Alert, { dismissible: true, ondismiss }); + alert.click('.Alert-dismiss'); + expect(ondismiss).toHaveBeenCalled(); + }); + + it('should not be dismissible if not chosen', function () { + const alert = mq(Alert, { type: 'error', dismissible: false }); + expect(alert).not.toHaveElement('button.Alert-dismiss'); + }); +}); +``` + +#### Methods + +These are the custom methods that are available for mithril component tests: +* **`toHaveElement(selector)`** - Checks if the component has an element that matches the given selector. +* **`toContainRaw(content)`** - Checks if the component HTML contains the given content. + +To negate any of these methods, simply prefix them with `not.`. For example, `expect(alert).not.toHaveElement('button.Alert-dismiss');`. For more information, check out the [Jest docs](https://jestjs.io/docs/using-matchers). For example you may need to check how to [mock functions](https://jestjs.io/docs/mock-functions), or how to use `beforeEach` and `afterEach` to set up and tear down tests. + + + +## E2E Tests + +Coming Soon! diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/theme.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/theme.md new file mode 100644 index 000000000..7890be47f --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/theme.md @@ -0,0 +1,27 @@ +# Themes + +Flarum "themes" are just extensions. Typically, you'll want to use the `Frontend` extender to register custom [Less](https://lesscss.org/#overview) and JS. Of course, you can use other extenders too: for example, you might want to support settings to allow configuring your theme. + +You can indicate that your extension is a theme by setting the "extra.flarum-extension.category" key to "theme". For example: + +```json +{ + // other fields + "extra": { + "flarum-extension": { + "category": "theme" + } + } + // other fields +} +``` + +All this will do is show your extension in the "theme" section in the admin dashboard extension list. + +## Less Variable Customization + +You can define new Less variables in your extension's Less files. There currently isn't an extender to modify Less variable values in the PHP layer, but this is planned for future releases. + +## Switching Between Themes + +Flarum doesn't currently have a comprehensive system that would support switching between themes. This is planned for future releases. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md new file mode 100644 index 000000000..7ba6adcbf --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md @@ -0,0 +1,257 @@ +# Updating For 1.0 + +Flarum version 1.0 is the long-awaited stable release! This release brings a number of refactors, cleanup, and small improvements that should make your Flarum experience just a bit better! + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Full Stack + +### Translations and transChoice + +#### Background + +Historically, Flarum has used Symfony for backend translations, and a port for frontend translations to keep format consistent. There are a few limitations to this approach though: + +- Developers need to decide between using `trans` or `transChoice` for pluralization +- The pluralization format is proprietary to Symfony +- We have to maintain the JS port ourselves +- Keys for values provided to backend translations need to be wrapped in curly braces. (e.g. `$this->translator->trans('some.translation', ['{username}' => 'Some Username!'])`). +- There's no support for complex applications (nested pluralization, non-number-based selection) +- As a result of the previous point, genderization is impossible. And that's kinda important for a lot of languages. + +### New System + +In v5, Symfony dropped their proprietary `transChoice` system in favor of the more-or-less standard [ICU MessageFormat](https://symfony.com/doc/5.2/translation/message_format.html). This solves pretty much every single one of the aforementioned issues. In this release, Flarum will be fully switching to ICU MessageFormat as well. What does this mean for extensions? + +- `transChoice` should not be used at all; instead, the variable passed for pluralization should be included in the data. +- Keys for backend translations no longer need to be surrounded by curly braces. +- Translations can now use the [`select` and `plural`](https://symfony.com/doc/5.2/translation/message_format.html) formatter syntaxes. For the `plural` formatter, the `offset` parameter and `#` magic variables are supported. +- These `select` and `plural` syntaxes can be nested to arbitrary depth. This is often a bad idea though (beyond, say, 2 levels), as things can get unnecessarily complex. + +No change to translation file naming is necessary (Symfony docs say that an `+intl-icu` suffix is necessary, but Flarum will now interpret all translation files as internationalized). + +#### Future Changes + +In the future, this will serve as a basis for additional features: + +- Translator preprocessors will allow extensions to modify arguments passed to translations. This will enable genderization (extensions could automatically extract a gender field from any objects of type "user" passed in). +- We could support internationalized "magic variables" for numbers: currently, `one` is supported, but others (`few`, `many`, etc) currently aren't. +- We could support ordinal formatting in additional to just plural formatting. + +#### Changes Needed in Extensions + +The `transChoice` methods in the frontend and backend have been removed. The `trans` method should always be used for translating, regardless of pluralization. If a translation requires pluralization, make sure you pass in the controlling variable as one of the arguments. + +In the frontend, code that looked like this: + +```js +app.translator.transChoice('some-translation', guestCount, {host: hostName}); +``` + +should be changed to: + +```js +// This uses ES6 key-property shorthand notation. {guestCount: guestCount} is equivalent to {guestCount} +app.translator.trans('some-translation', {host: hostName, guestCount }); +``` + +Similarly, in the backend, + +```php +$translator->transChoice('some-translation', $guestCount, ['{host}' => $hostName]); +``` + +should be changed to: + +```php +$translator->trans('some-translation', ['host' => $hostName, 'guestCount' => $guestCount]); +``` + +Note that in the backend, translation keys were previously wrapped in curly braces. This is no longer needed. + +#### Changes Needed in Translations + +Translations that aren't using pluralization don't need any changes. + +Pluralized translations should be changed as follows: + +`For {count} minute|For {count} minutes` + +to + +`{count, plural, one {For # minute} other {For # minutes}}` + +Note that in this example, `count` is the variable that controls pluralization. If a different variable were used (such as guestCount in the example above), this would look like: + +`{guestCount, plural, one {For # minute} other {For # minutes}}` + +See [our i18n docs](i18n.md) for more information. + +### Permissions Changes + +For a long time, the `viewDiscussions` and `viewUserList` permissions have been confusing. Despite their names: + +- `viewDiscussions` controls viewing both discussions and users. +- `viewUserList` controls searching users, not viewing user profiles. + +To clear this up, in v1.0, these permissions have been renamed to `viewForum` and `searchUsers` respectively. A migration in core will automatically adjust all permissions in the database to use the new naming. However, any extension code using the old name must switch to the new ones immediately to avoid security issues. To help the transfer, a warning will be thrown if the old permissions are referenced. + +We have also slightly improved tag scoping for permissions. Currently, permissions can be applied to tags if: + +- The permission is `viewForum` +- The permission is `startDiscussion` +- The permission starts with `discussion.` + +However, this doesn't work for namespaced permissions (`flarum-acme.discussion.bookmark`), or permissions that don't really have anything to do with discussions, but should still be scoped (e.g. `viewTag`). To counter this, a `tagScoped` attribute can be used on the object passed to [`registerPermission`](admin.md) to explicitly indicate whether the permission should be tag scopable. If this attribute is not provided, the current rules will be used to determine whether the permission should be tag scopable. + +## Frontend + +### Tooltip Changes + +The `flarum/common/components/Tooltip` component has been introduced as a simpler and less framework-dependent way to add tooltips. If your code is creating tooltips directly (e.g. via `$.tooltip()` in `oncreate` methods), you should wrap your components in the `Tooltip` component instead. For example: + +```tsx + + + +``` + +See [the source code](https://github.com/flarum/core/blob/master/js/src/common/components/Tooltip.tsx) for more examples and instructions. + +See [the PR](https://github.com/flarum/core/pull/2843/files) for examples of how to change existing code to use tooltips. + +### PaginatedListState + +The `flarum/common/states/PaginatedListState` state class has been introduced to abstract away most of the logic of `DiscussionListState` and `NotificationListState`. It provides support for loading and displaying paginated lists of JSON:API resources (usually models). In future releases, we will also provide an `PaginatedList` (or `InfiniteScroll`) component that can be used as a base class for these paginated lists. + +Please see [the source code](https://github.com/flarum/core/blob/master/js/src/common/states/PaginatedListState.ts) for a list of methods. + +Note that `flarum/forum/states/DiscussionListState`'s `empty` and `hasDiscussions` methods have been removed, and replaced with `isEmpty` and `hasItems` respectively. This is a breaking change. + +### New Loading Spinner + +The old `spin.js` based loading indicator has been replaced with a CSS-based solution. For the most part, no changes should be needed in extensions, but in some cases, you might need to update your spinner. This change also makes it easier to customize the spinner. + +See [this discussion](https://discuss.flarum.org/d/26994-beta16-using-the-new-loading-spinner) for more information. + +### classList util + +Ever wrote messy code trying to put together a list of classes for some component? Well, no longer! The [clsx library](https://www.npmjs.com/package/clsx) is now available as the `flarum/common/utils/classList` util. + +### User List + +An extensible user list has been added to the admin dashboard. In future releases, we hope to extract a generic model table component that can be used to list any model in the admin dashboard. + +See [the source code](https://github.com/flarum/core/blob/master/js/src/admin/components/UserListPage.tsx#L41) for a list of methods to extend, and examples of how columns should look like (can be added by extending the `columns` method and adding items to the [ItemList](frontend.md)). + +### Miscellaneous + +- Components should now call `super` for ALL Mithril lifecycle methods they define. Before, this was only needed for `oninit`, `onbeforeupdate`, and `oncreate`. Now, it is also needed in `onupdate`, `onbeforeremove`, and `onremove`. See [this GitHub issue](https://github.com/flarum/core/issues/2446) for information on why this change was made. +- The `flarum/common/utils/insertText` and `flarum/common/utils/styleSelectedText` utils have been moved to core from `flarum/markdown`. See `flarum/markdown` for an example of usage. +- The `extend` and `override` utils can now modify several methods at once by passing in an array of method names instead of a single method name string as the second argument. This is useful for extending the `oncreate` and `onupdate` methods at once. +- The `EditUserModal` component is no longer available through the `flarum/forum` namespace, it has been moved to `flarum/common`. Imports should be adjusted. +- The `Model` and `Route` JS extenders have been removed for now. There aren't currently used in any extensions that we know of. We will be reintroducing JS extenders during v1.x releases. +- The `Search` component can now be used with the `SearchState` state class. Previously, `SearchState` was missing the `getInitialSearch` method expected by the `Search` component. + +## Backend + +### Filesystem Extenders + +In this release, we refactored our use of the filesystem to more consistently use [Laravel's filesystem API](https://laravel.com/docs/8.x/filesystem). Extensions can now declare new disks, more easily use core's `flarum-assets` and `flarum-avatars` disks, and create their own storage drivers, enabling CDN and cloud storage support. + +### Compat and Closure Extenders + +In early Flarum versions, the `extend.php` file allowed arbitrary functions that allowed execution of arbitrary code one extension boot. For example: + +```php +return [ + // other extenders + function (Dispatcher $events) { + $events->subscribe(Listener\FilterDiscussionListByTags::class); + $events->subscribe(Listener\FilterPostsQueryByTag::class); + $events->subscribe(Listener\UpdateTagMetadata::class); + } +]; +``` + +This approach was difficult to maintain and provide a well-tested public API for, frequently resolved classes early (breaking all sorts of things), and was not very descriptive. With the extender API completed in beta 16, this approach is no longer necessary. Support for these closures has been removed in this stable version. + +One type of functionality for which the extender replacement isn't obvious is container bindings ([e.g. flarum/pusher](https://github.com/flarum/pusher/blob/v0.1.0-beta.14/extend.php#L33-L49)). This can be done with via the service provider extender (e.g. [a newer version of flarum/pusher](https://github.com/flarum/pusher/blob/master/extend.php#L40-L41)). + +If you are unsure about which extenders should be used to replace your use of callbacks in `extend.php`, or are not sure that such an extender exists, please comment so below or reach out! We're in the final stages of finishing up the extender API, so now is the time to comment. + +### Scheduled Commands + +The [fof/console](https://github.com/FriendsOfFlarum/console) library has been a popular way to schedule commands (e.g. for publishing scheduled posts, running DB-heavy operations, etc) for several release. In Flarum 1.0, this functionality has been brought into core's `Console` extender. See our [console extension documentation](console.md) for more information on how to create schedule commands, and our [console user documentation](../console.md) for more information on how to run scheduled commands. + +### Eager Loading Extender + +As part of solving [N+1 Query issues](https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/) in some [Flarum API endpoints](https://github.com/flarum/core/issues/2637), we have introduced a `load` method on the `ApiController` extender that allows you to indicate relations that should be eager loaded. + +This should be done if you know a relation will always be included, or will always be referenced by controller / permission logic. For example, we will always need the tags of a discussion to check what permissions a user has on that discussion, so we should eager load the discussion's `tags` relationship. For example: + +```php +return [ + // other extenders + (new Extend\ApiController(FlarumController\ListDiscussionsController::class)) + ->addInclude(['tags', 'tags.state', 'tags.parent']) + ->load('tags'), +]; +``` + +### RequestUtil + +The `Flarum\Http\RequestUtil`'s `getActor` and `withActor` should be used for getting/setting the actor (user) on requests. `$request->getAttribute('actor')` and `$request->withAttribute('actor')` are deprecated, and will be removed in v2.0. + +### Miscellaneous + +- The `Formatter` extender now has an `unparse` method that allows modifying XML before unparsing content. +- All route names must now be unique. In beta 16, uniqueness was enforced per-method; now, it is mandatory for all routes. +- API requests sent through `Flarum\Api\Client` now run through middleware, including `ThrottleApi`. This means that it is now possible to throttle login/registration calls. +- In beta 16, registering custom [searchers](search.md) was broken. It has been fixed in stable. +- The `post_likes` table in the [flarum/likes](https://github.com/flarum/likes) extension now logs the timestamp when likes were created. This isn't used in the extension, but could be used in other extensions for analytics. +- The `help` attribute of [admin settings](admin.md) no longer disappears on click. +- The `generate:migration` console command has been removed. The [Flarum CLI](https://discuss.flarum.org/d/26525-rfc-flarum-cli-alpha) should be used instead. +- The `GambitManager` util class is now considered internal API, and should not be used directly by extensions. +- The `session` attribute is no longer available on the `User` class. This caused issues with queue drivers, and was not conceptually correct (a user can have multiple sessions). The current session is still available via the `$request` instance. +- The `app`, `base_path`, `public_path`, `storage_path`, and `event` global helpers have been restored, but deprecated perpetually. These exist in case Laravel packages need them; they **should not** be used directly by Flarum extension code. The `flarum/laravel-helpers` package has been abandoned. +- The following deprecated features from beta 16 have been removed: + - The `TextEditor`, `TextEditorButton`, and `SuperTextarea` components are no longer exported through the `flarum/forum` namespace, but through `flarum/common` (with the exception of `SuperTextarea`, which has been replaced with `flarum/common/utils/BasicEditorDriver`). + - Support for `Symfony\Component\Translation\TranslatorInterface` has been removed, `Symfony\Contracts\Translation\TranslatorInterface` should be used instead. + - All backwards compatibility layers for the [beta 16 access token refactors](update-b16.md#access-token-and-authentication-changes) have been removed + - The `GetModelIsPrivate` event has been removed. The `ModelPrivate` extender should be used instead. + - The `Searching` (for both `User` and `Discussion` models), `ConfigureAbstractGambits`, `ConfigureDiscussionGambits`, and `ConfigureUserGambits` events have been removed. The `SimpleFlarumSearch` extender should be used instead. + - The `ConfigurePostsQuery` event has been removed. The `Filter` extender should be used instead. + - The `ApiSerializer` extender's `mutate` method has been removed. The same class's `attributes` method should be used instead. + - The `SearchCriteria` and `SearchResults` util classes have been removed. `Flarum\Query\QueryCriteria` and `Flarum\Query\QueryResults` should be used instead. + - The `pattern` property of `AbstractRegexGambit` has been removed; the `getGambitPattern` method is now a required abstract method. + - The `AbstractSearch` util class has been removed. `Flarum\Search\SearchState` and `Flarum\Filter\FilterState` should be used instead. + - The `CheckingPassword` event has been removed, the `Auth` extender should be used instead. + +## Tags Extension Changes + +As mentioned above, [tag scopable permissions](#permissions-changes) can now be explicitly declared. + +We've also made several big refactors to significantly improve tags performance. + +Firstly, the [Tag](https://github.com/flarum/tags/blob/d093ca777ba81f826157522c96680717d3a90e24/src/Tag.php#L38-L38) model's static `getIdsWhereCan` and `getIdsWhereCannot` methods have been removed. These methods scaled horribly on forums with many tags, sometimes adding several seconds to response time. + +These methods have been replaced with a `whereHasPermission` [Eloquent dynamic scope](https://laravel.com/docs/8.x/eloquent#dynamic-scopes) that returns a query. For example: + +`Tag::whereHasPermission($actor, 'viewDiscussions)`. + +That query can then be used in other DB queries, or further constricted to retrieve individual tags. + +Secondly, we no longer load in all tags as part of the initial payload. The initial payload contains all top-level primary tags, and the top 3 secondary tags. Other tags are loaded in as needed. Future releases will paginate secondary tags. This should enable forums to have thousands of secondary tags without significant performance impacts. These changes mean that extensions should not assume that all tags are available in the model store. + +## Testing Library Changes + +- Bundled extensions will not be automatically enabled; all enabled extensions must be specified in that test case. +- `setting` and `config` methods have been added that allow configuring settings and config.php values before the tested application boots. See [the testing docs](testing.md) for more information. +- The `php flarum test:setup` command will now drop the existing test DB tables before creating the database. This means that you can run `php flarum test:setup` to ensure a clean database without needing to go into the database and drop tables manually. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md new file mode 100644 index 000000000..ed17364ed --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md @@ -0,0 +1,139 @@ +# Updating For 1.x + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## 1.7 + +### Frontend + +- Frontend extenders similar to the backend have been added, we highly recommend using them instead of the old method (https://docs.flarum.org/extend/models#adding-new-models-1), (https://docs.flarum.org/extend/routes#frontend-routes). +- There is a new tag selection component (https://github.com/flarum/framework/blob/360a2ba1d886df3fc6d326be932c5431ee9df8cf/extensions/tags/js/src/common/components/TagSelectionModal.tsx). + +### Backend + +- Support for php 8.2, deprecations are still thrown by some packages, the testing workflow has been updated to ignore deprecations on 8.2 +- The `/api` endpoint now contains the actor as an included relationship. +- The `Model::dateAttribute($attribute)` extender is deprecated, use `Model::cast($attribute, 'datetime')` instead. + +### Tooling + +- New `phpstan` package to run static code analysis on your extensions for code safety (https://docs.flarum.org/extend/static-code-analysis). +- New `jest-config` package to run frontend unit and component tests (https://docs.flarum.org/extend/testing). + +## 1.6 Changes + +### Backend + +- Added customizable session drivers through the `Session` extender. + +## 1.5 Changes + +### Frontend + +- More portions of the frontend are now written in TypeScript, providing a better extension development experience. +- Modals can be used in stacks, allowing for multiple modals to be open at once. This is useful for modals that open other modals: `app.modal.show(ModalComponent, { attrs }, true)`. + +### Backend + +- There is a new `createTableIfNotExists` migration helper, which can be used to create tables only if they don't already exist. + +## 1.4 Changes + +No developer-facing changes were made in Flarum v1.4. + +## 1.3 Changes + +Flarum v1.3 included mostly QoL improvements. Below are listed note worthy changes for extension developers: + +### Frontend + +- More portions of the frontend are now written in TypeScript, providing a better extension development experience. +- Frontend errors will no longer cause the forum to crash into a NoJs page. The extension will fail to execute its frontend code (initializer) and display an error to the admin through an alert, and to all users through the console. The frontend will continue to execute without the extension's frontend changes. +- The markdown toolbar can now be used on the admin side. + +### Backend + +- Calculation of the `number` attribute on `posts` has changed and no longer relies on the discussion model's `post_number_index` attribute which is now deprecated and will be removed in 2.0 +- Extension event listeners are now added after core even listeners, this should generally cause no changes in behavior. + +### Tooling + +- The backend tests workflow now automatically fails tests if there are any PHP warnings and notices. + +## 1.2 Changes + +Flarum v1.2 included quite a few bugfixes, internal refactors, and new features. The following recaps the most important changes for extension developers: + +### Frontend + +- Flarum core now passes TypeScript type checking (on the portion written in TypeScript). Additionally, major portions of the frontend (models, the application instance, and others) are now written in TypeScript. These changes should make it much easier and more fruitful to write extensions in TypeScript. +- Instead of directly using Less variables in CSS code, core now uses CSS variables. For the most part, we've just created CSS variables and set their values to the Less variables. This should make theming and customizing CSS a lot easier. https://github.com/flarum/core/pull/3146. +- Dropdowns can now be lazy-drawn to improve performance. You can do this by setting the lazy draw attr to "true". https://github.com/flarum/core/pull/2925. +- [Textarea-type settings](https://github.com/flarum/core/pull/3141) are now supported through the `app.extensionData.registerSetting` util. +- You can now use Webpack 5 to bundle your extension's code. This will offer minor bundle size improvements. +- A new `flarum/common/components/ColorPreviewInput` component [has been added](https://github.com/flarum/core/pull/3140). It can be used directly, or through the `color-preview` type when registered via `app.extensionData.registerSetting`. +- Extensions can now [modify the minimum search length](https://github.com/flarum/core/pull/3130) of the `Search` component. +- The following components are now extensible: + - The "colors" part of the Appearance page in the admin dashboard: https://github.com/flarum/core/pull/3186 + - The `StatusWidget` dropdown in the admin dashboard: https://github.com/flarum/core/pull/3189 + - `primaryControls` in the notification list: https://github.com/flarum/core/pull/3204 +- Extensions now have finer control over positioning when adding elements to the DiscussionPage sidebar items: https://github.com/flarum/core/pull/3165 +- + +### Backend + +- An [extender for settings defaults](https://github.com/flarum/core/pull/3127) has been added. This should be used instead of the `addSettings` migration helper, which has been deprecated. +- You can now [generate Less variables from setting values](https://github.com/flarum/core/pull/3011) via the `Settings` extender. +- Extensions can now [override/supplement blade template namespaces](https://github.com/flarum/core/pull/3167) through the `View` extender, meaning custom blade templates can be used instead of the default ones added by core or extensions. +- You can now define [custom Less functions through PHP](https://github.com/flarum/core/pull/3190), allowing you to use some backend logic in your Less theming. +- Extensions can now create [custom page title drivers](https://github.com/flarum/core/pull/3109/files) for titles in server-returned HTML. +- Custom logic can now be used when [deciding which relations to eager-load](https://github.com/flarum/core/pull/3116). +- Events [are now dispatched](https://github.com/flarum/core/pull/3203) for the `Notification\Read` and `Notification\ReadAll` events. +- An `ImageManager` instance is now [bound into the container](https://github.com/flarum/core/pull/3195), and can be configured to use either the `gd` or `imagick` backing drivers via the `"intervention.driver"` key in `config.php`. +- User IP addresses are now passed to the [API Client](https://github.com/flarum/core/pull/3124). +- A custom revision versioner implentation [can be set via container bindings](https://github.com/flarum/core/pull/3183) to customize how asset versions are named. +- A SlugManager instance [is now available](https://github.com/flarum/core/pull/3194) in blade templates via the `slugManager` variable. + +### Misc + +- Translations now support the `zero`, `one`, `two`, `few`, and `many` localized plural rules for `plural` ICU MessageFormat translations. This was done through the [`Intl.PluralRules` helper](https://github.com/flarum/core/issues/3072). +- Translations are now used for page titles, so that the format can be customized via language packs or [Linguist](https://discuss.flarum.org/d/7026-linguist-customize-translations-with-ease): https://github.com/flarum/core/pull/3077, https://github.com/flarum/core/pull/3228 +- API endpoints for retrieving single groups, as well as support for filtering groups on the plural get endpoint, [have been added](https://github.com/flarum/core/pull/3084). + + +### Tooling + + +- The `flarum-cli infra` command can now be used to update or enable various infrastructure features. You can now add the following to your extension in just one command: + - TypeScript + - Prettier for JS/TS formatting + - Backend testing with PHPUnit + - Code formatting with StyleCI + - EditorConfig support + - GitHub actions for automating testing, linting, type checking, and building. +- You can also exclude any files from these updates by adding their relative path to the "extra.flarum-cli" key's array in your extension's `composer.json` file. For example, if you wanted to exclude your tsconfig file from any updates by the infra system, the "extra.flarum-cli" key's value should be `["js/tsconfig.json"]`. +- The `flarum-cli audit infra` can be used to check that all infra modules your extension uses are up to date. The `--fix` flag can be used to automatically fix any issues, which has essentially the same effect as running `flarum-cli infra` for each outdated module. +- All `flarum-cli` commands can now be run with a `--no-interaction` flag to prevent prompts. Defaults will be used when possible, and errors will be thrown if a prompt is needed and there is no default. +- Frontend GH actions now support type-checking, as well as type coverage reports. + +## 1.1 Changes + +Flarum version 1.1 mostly focuses on bugfixes and quality-of-life improvements following our stable release earlier this year. These are mainly user-facing and internal infrastructure changes, so extensions are not significantly affected. + +### Frontend + +- Flarum now has an organization-wide prettier config package under [`@flarum/prettier-config`](https://github.com/flarum/prettier-config). +- Most custom (setting or data based) coloring in core is now done via [CSS custom properties](https://github.com/flarum/core/pull/3001). +- Typehinting for Flarum's globals are now [supported in extensions](https://github.com/flarum/core/pull/2992). +- You can now pass extra attrs to the `Select` component, and they will be [passed through to the DOM](https://github.com/flarum/core/pull/2959). +- The `DiscussionPage` component is now organized [as an item list](https://github.com/flarum/core/pull/3004), so it's easier for extensions to change its content. +- Extensions [can now edit](https://github.com/flarum/core/pull/2935) the `page` parameter of `PaginatedListState`. + +### Backend + +- Flarum now comes with a [Preload extender](https://github.com/flarum/core/pull/3057) for preloading any custom frontend assets. +- A new [Theme](https://github.com/flarum/core/pull/3008) extender now allows overriding Less files and internal imports. This allows themes to more easily completely replace Less modules. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md new file mode 100644 index 000000000..aaa98a2a5 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md @@ -0,0 +1,53 @@ +# Updating For Beta 10 + +Beta 10 further solidifies the core architecture, offering new extenders as a stable, use-case-driven API for extending Flarum's core. A few small changes may necessitate updates to your extensions to make them compatible with Beta 10. These are detailed below. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Breaking Changes + +- The `Flarum\Event\GetDisplayName` class has been moved to `Flarum\User\Event\GetDisplayName`. +- The `Flarum\Http\Exception\ForbiddenException` has been removed. Use `Flarum\User\Exception\PermissionDeniedException` instead. +- The `assertGuest()` method of the `Flarum\User\AssertPermissionTrait` has been removed without replacement. +- Old error handling middleware and exception handler classes were removed (see "New Features" for more details): + - `Flarum\Api\Middleware\HandleErrors` + - `Flarum\Http\Middleware\HandleErrorsWithView` + - `Flarum\Http\Middleware\HandleErrorsWithWhoops` + - `Flarum\Api\ErrorHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + - `Flarum\Api\ExceptionHandler\FloodingExceptionHandler` + - `Flarum\Api\ExceptionHandler\IlluminateValidationExceptionHandler` + - `Flarum\Api\ExceptionHandler\InvalidAccessTokenExceptionHandler` + - `Flarum\Api\ExceptionHandler\InvalidConfirmationTokenExceptionHandler` + - `Flarum\Api\ExceptionHandler\MethodNotAllowedExceptionHandler` + - `Flarum\Api\ExceptionHandler\ModelNotFoundExceptionHandler` + - `Flarum\Api\ExceptionHandler\PermissionDeniedExceptionHandler` + - `Flarum\Api\ExceptionHandler\RouteNotFoundExceptionHandler` + - `Flarum\Api\ExceptionHandler\TokenMismatchExceptionHandler` + - `Flarum\Api\ExceptionHandler\ValidationExceptionHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + +## Recommendations + +- We tweaked the [recommended flarum/core version constraints for extensions](start.md#composer-json). We now recommend you mark your extension as compatible with the current and the upcoming beta release. (For beta.10, that would be any beta.10.x and beta.11.x version.) The core team will strive to make this work well by deprecating features before removing them. More details on this change in [this pull request](https://github.com/flarum/docs/pull/75). + +## New Features + +- New, extensible **error handling** stack in the `Flarum\Foundation\ErrorHandling` namespace: The `Registry` maps exceptions to "types" and HTTP status codes, `HttpFormatter` instances turn them into HTTP responses. Finally, `Reporter` instances are notified about unknown exceptions. + - You can build custom exception classes that will abort the current request (or console command). If they have semantic meaning to your application, they should implement the `Flarum\Foundation\KnownError` interface, which exposes a "type" that is used to render pretty error pages or dedicated error messages. + - More consistent use of HTTP 401 and 403 status codes. HTTP 401 should be used when logging in (i.e. authenticating) could make a difference; HTTP 403 is reserved for requests that fail because the already authenticated user is lacking permissions to do something. + - The `assertRegistered()` and `assertPermission()` methods of the `Flarum\User\AssertPermissionTrait` trait have been changed to match above semantics. See [this pull request](https://github.com/flarum/core/pull/1854) for more details. + - Error views are now determined based on error "type", not on status code (see [bdac88b](https://github.com/flarum/core/commit/bdac88b5733643b9c5dabae9e09a64d9f6e41d58)) +- **Queue support**: This release incorporates Laravel's illuminate/queue package, which allows offloading long-running tasks (such as email sending or regular cleanup jobs) onto a dedicated worker process. These changes are mostly under the hood, the next release(s) will start using the queue system for sending emails. By default, Flarum will use the "sync" queue driver, which executes queued tasks immediately. This is far from ideal and mostly guarantees a hassle-free setups. Production-grade Flarum installs are expected to upgrade to a more full-featured queue adapter. +- The `Flarum\Extend\LanguagePack` now accepts an optional path in its constructor. That way, language packs can store their locales in a different directory if they want to. +- The `formatContent()` method of `Flarum\Post\CommentPost` can now be called without an HTTP request instance, e.g. when rendering a post in an email template. + +## Deprecations + +- **Reminder**: In previous versions of Flarum, an extensions' main file was named `bootstrap.php`. This name will no longer be supported in the stable 0.1 release. Make sure your extension uses the name `extend.php`. +- Laravel's global string and array helpers (e.g. `str_contains()` and `array_only()`) are deprecated in favor of their class based alternatives (`Illuminate\Support\Str::contains()` and `Illuminate\Support\Arr::only()`). See the [announcement](https://laravel-news.com/laravel-5-8-deprecates-string-and-array-helpers) and [pull request](https://github.com/laravel/framework/pull/26898) for more information. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md new file mode 100644 index 000000000..ce6b1aca2 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md @@ -0,0 +1,34 @@ +# Updating For Beta 12 + +Beta 12 packs several new features for extension developers, but also continues our cleanup efforts which results in a few changes, so please read this guide carefully to find out whether your extensions are affected. We invested extra effort to introduce new functionality in a backward-compatible manner or first deprecate functionality before it will be removed in the next release, in line with our [versioning recommendations](start.md#composer-json). + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Deprecations / Upcoming breaking changes + +- **Reminder**: In previous versions of Flarum, an extensions' main file was named `bootstrap.php`. This name will no longer be supported in the stable 0.1 release. Make sure your extension uses the name `extend.php`. +- PHP 7.1 support will be dropped in beta.13. +- Using library classes from the `Zend` namespace is now deprecated and will be removed in beta.13. Use the `Laminas` namespace instead. See [PR #1963](https://github.com/flarum/core/pull/1963). +- The `Flarum\Util\Str::slug()` method has been deprecated. Use `Illuminate\Support\Str::slug()` instead. +- The `Flarum\Event\ConfigureMiddleware` has been deprecated. We finally have a [proper replacement](middleware.md) - see "New Features" below. Therefore, it will be removed in beta.13. +- If you implement the `Flarum\Mail\DriverInterface`: + - Returning a plain array of field names from the `availableSettings()` method is deprecated, but still supported. It must now return an array of field names mapping to their type. See [the inline documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L25-L32) for more details. + - Implement the `validate()` method that will be required in beta.13. See [its documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L34-L48). + - Implement the `canSend()` method that will be required in beta.13. See [its documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L50-L54). + +## New Features + +- New **PHP extenders**: + - `Flarum\Extend\Middleware` offers methods for adding, removing or replacing middleware in our three middleware stacks (api, forum, admin). We also added [documentation](middleware.md) for this feature. + - `Flarum\Extend\ErrorHandling` lets you configure status codes and other aspects of our error handling stack depending on error types or exception classes. +- **JavaScript**: + - The `flarum/components/Select` component now supports a `disabled` prop. See [PR #1978](https://github.com/flarum/core/pull/1978). + +## Other changes / Recommendations + +- The `TextFormatter` library has been updated to (at least) version 2.3.6. If you are using it (likely through our own `Flarum\Formatter\Formatter` class), we recommend scanning [the library's changelog](https://github.com/s9e/TextFormatter/blob/2.3.6/CHANGELOG.md). +- The JS `slug()` helper from the `flarum/utils/string` module should only be used to *suggest* slugs to users, not enforce them. It does not employ any sophisticated transliteration logic like its PHP counterpart. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md new file mode 100644 index 000000000..1b19a9714 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md @@ -0,0 +1,40 @@ +# Updating For Beta 13 + +Beta 13 ships with several new extenders to simplify building and maintaining extensions. We do our best to create backward compatibility changes. We recommend changing to new Extenders as soon as they are available. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Breaking Changes + +- Dropped support for PHP 7.1. +- Classes from the `Zend` namespace are now removed. Use the `Laminas` namespace instead. See [PR #1963](https://github.com/flarum/core/pull/1963). +- The `Flarum\Util\Str::slug()` method has been removed including the class. Use `Illuminate\Support\Str::slug()` instead. +- The `Flarum\Event\ConfigureMiddleware` has been removed. Use the [proper replacement](middleware.md). +- Several events used in Event Listeners have been removed, use their [replacement extender](start.md#extenders) instead. +- The LanguagePack extender only loads keys from extensions that are enabled. The translations loaded are based on the yaml files matching the [i18n namespace](i18n.md#appendix-a-standard-key-format). +- All notifications are now sent through the queue; without a queue driver they will run as usual. +- The implementation of avatar upload changed, we're [no longer storing files temporarily on disk](https://github.com/flarum/core/pull/2117). +- The SES mail driver [has been removed](https://github.com/flarum/core/pull/2011). +- Mail driver backward compatibility from beta 12 has been removed, use the new Mail extender or implement the [modified interface](https://github.com/flarum/core/blob/master/src/Mail/DriverInterface.php). + +## Recommendations + +- Beta 14 will ship with a rewrite in the frontend (javascript). If you're building for that release, make sure to follow our [progress](https://github.com/flarum/core/pull/2126). + +## New Features + +- A ton of new extenders: + - [Middleware extender](https://github.com/flarum/core/pull/2017) + - [Console extender](https://github.com/flarum/core/pull/2057) + - [CSRF extender](https://github.com/flarum/core/pull/2095) + - [Event extender](https://github.com/flarum/core/pull/2097) + - [Mail extender](https://github.com/flarum/core/pull/2012) + - [Model extender](https://github.com/flarum/core/pull/2100) + +## Deprecations + +- Several events [have been marked deprecated](https://github.com/flarum/core/commit/4efdd2a4f2458c8703aae654f95c6958e3f7b60b) to be removed in beta 14. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md new file mode 100644 index 000000000..deafdc960 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md @@ -0,0 +1,757 @@ +# Updating For Beta 14 + +This release brings a large chunk of breaking changes - hopefully the last chunk of this size before our stable release. In order to prepare the codebase for the upcoming stable release, we decided it was time to modernize / upgrade / exchange some of the underlying JavaScript libraries that are used in the frontend. Due to the nature and size of these upgrades, we have to pass on some of the breaking changes to you, our extension developers. + +On the bright side, this overdue upgrade brings us closer to the conventions of best practices of [Mithril.js](https://mithril.js.org/), the mini-framework used for Flarum's UI. Mithril's 2.0 release sports a more consistent component interface, which should be a solid foundation for years to come. Where possible, we replicated old APIs, to ease the upgrade and give you time to do the full transition. Quite a few breaking changes remain, though - read more below. + +:::tip + +If you need help with the upgrade, our friendly community will gladly help you out either [on the forum](https://discuss.flarum.org/t/extensibility) or [in chat](https://flarum.org/chat/). + +::: + +To ease the process, we've clearly separated the changes to the [frontend (JS)](#frontend-javascript) from those in the [backend (PHP)](#backend-php) below. If your extension does not change the UI, consider yourself lucky. :-) + +A [summary of the frontend changes](#required-frontend-changes-recap) is available towards the end of this guide. + +## Frontend (JavaScript) + +### Mithril 2.0: Concepts + +Most breaking changes required by beta 14 are prompted by changes in Mithril 2. [Mithril's upgrade guide](https://mithril.js.org/migration-v02x.html) is an extremely useful resource, and should be consulted for more detailed information. A few key changes are explained below: + +#### props -> attrs; initProps -> initAttrs + +Props passed into component are now referred to as `attrs`, and can be accessed via `this.attrs` where you would prior use `this.props`. This was done to be closer to Mithril's preferred terminology. We have provided a temporary backwards compatibility layer for `this.props`, but recommend using `this.attrs`. + +Accordingly, `initProps` has been replaced with `initAttrs`, with a similar BC layer. + +#### m.prop -> `flarum/utils/Stream` + +Mithril streams, which were available via `m.prop` in Mithril 0.2, are now available via `flarum/utils/Stream`. `m.prop` will still work for now due to a temporary BC layer. + +#### m.withAttr -> withAttr + +The `m.withAttr` util has been removed from Mithril. We have provided `flarum/utils/withAttr`, which does the same thing. A temporary BC layer has been added for `m.withAttr`. + +#### Lifecycle Hooks + +In mithril 0.2, we had 2 "lifecycle hooks": + +`init`, an unofficial hook which ran when the component instance was initialized. + +`config`, which ran when components were created, and on every redraw. + + +Mithril 2 has the following hooks; each of which take `vnode` as an argument: + +- `oninit` +- `oncreate` +- `onbeforeupdate` +- `onupdate` +- `onbeforeremove` +- `onremove` + +Please note that if your component is extending Flarum's helper `Component` class, you must call `super.METHOD(vnode)` if using `oninit`, `oncreate`, and `onbeforeupdate`. + +More information about what each of these do can be found [in Mithril's documentation](https://mithril.js.org/lifecycle-methods.html). + +A trivial example of how the old methods map to the new is: + +```js +class OldMithrilComponent extends Component { + init() { + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + config(element, isInitialized) { + console.log('Code to run on every redraw AND when the element is first attached'); + + if (isInitialized) return; + + console.log('Code to execute only once when components are first created and attached to the DOM'); + + context.onunload = () => { + console.log('Code to run when the component is removed from the DOM'); + } + } + + view() { + // In mithril 0, you could skip redrawing a component (or part of a component) by returning a subtree retain directive. + // See https://mithril.js.org/archive/v0.2.5/mithril.render.html#subtree-directives + // dontRedraw is a substitute for logic; usually, this is used together with SubtreeRetainer. + if (dontRedraw()) return { subtree: 'retain' }; + + return

Hello World!

; + } +} + +class NewMithrilComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + oncreate(vnode) { + super.oncreate(vnode); + + console.log('Code to run when components are first created and attached to the DOM'); + } + + onbeforeupdate(vnode, oldVnode) { + super.onbeforeupdate(vnode); + + console.log('Code to run BEFORE diffing / redrawing components on every redraw'); + + // In mithril 2, if we want to skip diffing / redrawing a component, we return "false" in its onbeforeupdate lifecycle hook. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeupdate + // This is also typically used with SubtreeRetainer. + if (dontRedraw()) return false; + } + + onupdate(vnode) { + // Unlike config, this does NOT run when components are first attached. + // Some code might need to be replicated between oncreate and onupdate. + console.log('Code to run on every redraw AFTER the DOM is updated.'); + } + + onbeforeremove(vnode) { + // This is run before components are removed from the DOM. + // If a promise is returned, the DOM element will only be removed when the + // promise completes. It is only called on the top-level component that has + // been removed. It has no equivalent in Mithril 0.2. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeremove + return Promise.resolve(); + } + + onremove(vnode) { + console.log('Code to run when the component is removed from the DOM'); + } +} +``` + +#### Children vs Text Nodes + +In Mithril 0.2, every child of a vnode is another vnode, stored in `vnode.children`. For Mithril 2, as a performance optimization, vnodes with a single text child now store that text directly in `vnode.text`. For developers, that means that `vnode.children` might not always contain the results needed. Luckily, text being stored in `vnode.text` vs `vnode.children` will be the same each time for a given component, but developers should be aware that at times, they might need to use `vnode.text` and not `vnode.children`. + +Please see [the mithril documentation](https://mithril.js.org/vnodes.html#structure) for more information on vnode structure. + +#### Routing API + +Mithril 2 introduces a few changes in the routing API. Most of these are quite simple: + +- `m.route()` to get the current route has been replaced by `m.route.get()` +- `m.route(NEW_ROUTE)` to set a new route has been replaced by `m.route.set(NEW_ROUTE)` +- When registering new routes, a component class should be provided, not a component instance. + +For example: + +```js +// Mithril 0.2 +app.routes.new_page = { path: '/new', component: NewPage.component() } + +// Mithril 2.0 +app.routes.new_page = { path: '/new', component: NewPage } +``` + +Additionally, the preferred way of defining an internal (doesn't refresh the page when clicked) link has been changed. The `Link` component should be used instead. + +```js +// Mithril 0.2 +Link Content + +// Mithril 2 +import Link from 'flarum/components/Link'; + +Link Content +``` + +You can also use `Link` to define external links, which will just render as plain `Children` html links. + +For a full list of routing-related changes, please see [the mithril documentation](https://mithril.js.org/migration-v02x.html). + +#### Redraw API + +Mithril 2 introduces a few changes in the redraw API. Most of these are quite simple: + +- Instead of `m.redraw(true)` for synchronous redraws, use `m.redraw.sync()` +- Instead of `m.lazyRedraw()`, use `m.redraw()` + +Remember that Mithril automatically triggers a redraw after DOM event handlers. The API for preventing a redraw has also changed: + +```js +// Mithril 0.2 + + +// Mithril 2 + +``` + +#### AJAX + +The `data` parameter of `m.request({...})` has been split up into `body` and `params`. + +For examples and other AJAX changes, see [the mithril documentation](https://mithril.js.org/migration-v02x.html#mrequest). + +#### Promises + +`m.deferred` has been removed, native promises should be used instead. For instance: + +```js +// Mithril 0.2 +const deferred = m.deferred(); + +app.store.find('posts').then(result => deferred.resolve(result)); + +return deferred.promise; + +// Mithril 2 +return app.store.find('posts'); +``` + +#### Component instances should not be stored + +Due to optimizations in Mithril's redrawing algorithms, [component instances should not be stored](https://mithril.js.org/components.html#define-components-statically,-call-them-dynamically). + +So whereas before, you might have done something like: + +```js +class ChildComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return

{this.counter}

; + } +} +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.child = new ChildComponent(); + } + + view() { + return ( +
+ + {this.child.render()} +
+ ) + } +} +``` + +That will no longer work. In fact; the Component class no longer has a render method. + +Instead, any data needed by a child component that is modified by a parent component should be passed in as an attr. For instance: + +```js +class ChildComponent extends Component { + view() { + return

{this.attrs.counter}

; + } +} + +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return ( +
+ + +
+ ) + } +} +``` + +For more complex components, this might require some reorganization of code. For instance, let's say you have data that can be modified by several unrelated components. In this case, it might be preferable to create a POJO "state instance' for this data. These states are similar to "service" singletons used in Angular and Ember. For instance: + +```js +class Counter { + constructor() { + this._counter = 0; + } + + increaseCounter() { + this._counter += 1; + } + + getCount() { + return this._counter; + } +} + +app.counter = new Counter(); + +extend(HeaderSecondary.prototype, 'items', function(items) { + items.add('counterDisplay', +
+

Counter: {app.counter.getCount()}

+
+ ); +}) + +extend(HeaderPrimary.prototype, 'items', function(items) { + items.add('counterButton', +
+ +
+ ); +}) +``` + +This "state pattern" can be found throughout core. Some non-trivial examples are: + +- PageState +- SearchState and GlobalSearchState +- NotificationListState +- DiscussionListState + +### Changes in Core + +#### Modals + +Previously, modals could be opened by providing a `Modal` component instance: + +```js +app.modal.show(new LoginModal(identification: 'prefilledUsername')); +``` + +Since we don't store component instances anymore, we pass in the component class and any attrs separately. + +```js +app.modal.show(LoginModal, {identification: 'prefilledUsername'}); +``` + +The `show` and `close` methods are still available through `app.modal`, but `app.modal` now points to an instance of `ModalManagerState`, not of the `ModalManager` component. Any modifications by extensions should accordingly be done to `ModalManagerState`. + +#### Alerts + +Previously, alerts could be opened by providing an `Alert` component instance: + +```js +app.alerts.show(new Alert(type: 'success', children: 'Hello, this is a success alert!')); +``` + +Since we don't store component instances anymore, we pass in a component class, attrs, children separately. The `show` method has 3 overloads: + +```js +app.alerts.show('Hello, this is a success alert!'); +app.alerts.show({type: 'success'}, 'Hello, this is a success alert!'); +app.alerts.show(Alert, {type: 'success'}, 'Hello, this is a success alert!'); +``` + +Additionally, the `show` method now returns a unique key, which can then be passed into the `dismiss` method to dismiss that particular alert. This replaces the old method of passing the alert instance itself to `dismiss`. + +The `show`, `dismiss`, and `clear` methods are still available through `app.alerts`, but `app.alerts` now points to an instance of `AlertManagerState`, not of the `AlertManager` component. Any modifications by extensions should accordingly be done to `AlertManagerState`. + +#### Composer + +Since we don't store a component instances anymore, a number of util methods from `Composer`, `ComposerBody` (and it's subclasses), and `TextEditor` have been moved onto `ComposerState`. + +For `forum/components/Composer`, `isFullScreen`, `load`, `clear`, `show`, `hide`, `close`, `minimize`, `fullScreen`, and `exitFullScreen` have been moved to `forum/states/ComposerState`. They all remain accessible via `app.composer.METHOD` + +A `bodyMatches` method has been added to `forum/states/ComposerState`, letting you check whether a certain subclass of `ComposerBody` is currently open. + +Various input fields are now stored as [Mithril Streams](https://mithril.js.org/stream.html) in `app.composer.fields`. For instance, to get the current composer content, you could use `app.composer.fields.content()`. Previously, it was available on `app.composer.component.content()`. **This is a convention that `ComposerBody` subclasses that add inputs should follow.** + +`app.composer.component` is no longer available. + +- Instead of `app.composer.component instanceof X`, use `app.composer.bodyMatches(X)`. +- Instead of `app.composer.component.props`, use `app.composer.body.attrs`. +- Instead of `app.composer.component.editor`, use `app.composer.editor`. + +For `forum/components/TextEditor`, the `setValue`, `moveCursorTo`, `getSelectionRange`, `insertAtCursor`, `insertAt`, `insertBetween`, `replaceBeforeCursor`, `insertBetween` methods have been moved to `forum/components/SuperTextarea`. + +Also for `forum/components/TextEditor`, `this.disabled` is no longer used; `disabled` is passed in as an attr instead. It may be accessed externally via `app.composer.body.attrs.disabled`. + +Similarly to Modals and Alerts, `app.composer.load` no longer accepts a component instance. Instead, pass in the body class and any attrs. For instance, + +```js +// Mithril 0.2 +app.composer.load(new DiscussionComposer({user: app.session.user})); + +// Mithril 2 +app.composer.load(DiscussionComposer, {user: app.session.user}) +``` + +Finally, functionality for confirming before unloading a page with an active composer has been moved into the `common/components/ConfirmDocumentUnload` component. + +#### Widget and DashboardWidget + +The redundant `admin/components/Widget` component has been removed. `admin/components/DashboardWidget` should be used instead. + +#### NotificationList + +For `forum/components/NotificationList`, the `clear`, `load`, `loadMore`, `parseResults`, and `markAllAsRead` methods have been moved to `forum/states/NotificationListState`. + +Methods for `isLoading` and `hasMoreResults` have been added to `forum/states/NotificationListState`. + +`app.cache.notifications` is no longer available; `app.notifications` (which points to an instance of `NotificationListState`) should be used instead. + +#### Checkbox + +Loading state in the `common/components/Checkbox` component is no longer managed through `this.loading`; it is now passed in as a prop (`this.attrs.loading`). + +#### Preference Saver + +The `preferenceSaver` method of `forum/components/SettingsPage` has been removed without replacement. This is done to avoid saving component instances. Instead, preferences should be directly saved. For instance: + +```js +// Old way +Switch.component({ + children: app.translator.trans('core.forum.settings.privacy_disclose_online_label'), + state: this.user.preferences().discloseOnline, + onchange: (value, component) => { + this.user.pushAttributes({ lastSeenAt: null }); + this.preferenceSaver('discloseOnline')(value, component); + }, +}) + +// Without preferenceSaver +Switch.component({ + children: app.translator.trans('core.forum.settings.privacy_disclose_online_label'), + state: this.user.preferences().discloseOnline, + onchange: (value) => { + this.discloseOnlineLoading = true; + + this.user.savePreferences({ discloseOnline: value }).then(() => { + this.discloseOnlineLoading = false; + m.redraw(); + }); + }, + loading: this.discloseOnlineLoading, +}) +``` + +A replacement will eventually be introduced. + +#### DiscussionListState + +For `forum/components/DiscussionList`, the `requestParams`, `sortMap`, `refresh`, `loadResults`, `loadMore`, `parseResults`, `removeDiscussion`, and `addDiscussion` methods have been moved to `forum/states/DiscussionListState`. + +Methods for `hasDiscussions`, `isLoading`, `isSearchResults`, and `empty` have been added to `forum/states/DiscussionListState`. + +`app.cache.discussions` is no longer available; `app.discussions` (which points to an instance of `DiscussionListState`) should be used instead. + +#### PageState + +`app.current` and `app.previous` no longer represent component instances, they are now instances of the `common/states/PageState` class. This means that: + +- Instead of `app.current instanceof X`, use `app.current.matches(X)` +- Instead of `app.current.PROPERTY`, use `app.current.get('PROPERTY')`. Please note that all properties must be exposed EXPLICITLY via `app.current.set('PROPERTY', VALUE)`. + +#### PostStream + +Logic from `forum/components/PostStreamScrubber`'s `update` method has been moved to `forum/components/PostStream`'s `updateScrubber` method. + +For `forum/components/PostStream`, the `update`, `goToFirst`, `goToLast`, `goToNumber`, `goToIndex`, `loadNearNumber`, `loadNearIndex`, `loadNext`, `loadPrevious`, `loadPage`, `loadRange`, `show`, `posts`, `reset`, `count`, and `sanitizeIndex` methods have been moved to `forum/states/PostStreamState`. + +Methods for `disabled` and `viewingEnd` have been added to `forum/states/PostStreamState`. + +#### SearchState and GlobalSearchState + +As with other components, we no longer store instances of `forum/components/Search`. As such, every `Search` component instance should be paired with a `forum/states/SearchState` instance. + +At the minimum, `SearchState` contains the following methods: + +- getValue +- setValue +- clear +- cache (adds a searched value to cache, meaning that we don't need to search for its results again) +- isCached (checks if a value has been searched for before) + +All of these methods have been moved from `Search` to `SearchState`. Additionally, Search's `stickyParams`, `params`, `changeSort`, `getInitialSearch`, and `clearInitialSearch` methods have been moved to `forum/states/GlobalSearchState`, which is now available via `app.search`. + +To use a custom search, you'll want to: + +1. Possibly create a custom subclass of `SearchState` +2. Create a custom subclass of `Search`, which overrides the `selectResult` method to handle selecting results as needed by your use case, and modify the `sourceItems` methods to contain the search sources you need. + +#### moment -> dayjs + +The `moment` library has been removed, and replaced by the `dayjs` library. The global `moment` can still be used for now, but is deprecated. `moment` and `dayjs` have very similar APIs, so very few changes will be needed. Please see the dayjs documentation [for more information](https://day.js.org/en/) on how to use it. + +#### Subtree Retainer + +`SubtreeRetainer` is a util class that makes it easier to avoid unnecessary redraws by keeping track of some pieces of data. When called, it checks if any of the data has changed; if not, it indicates that a redraw is not necessary. + +In mithril 0.2, its `retain` method returned a [subtree retain directive](https://mithril.js.org/archive/v0.1.25/mithril.render.html#subtree-directives) if no redraw was necessary. + +In mithril 2, we use its `needsRebuild` method in combination with `onbeforeupdate`. For instance: + +```js +class CustomComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + this.showContent = false; + + this.subtree = new SubtreeRetainer( + () => this.showContent, + ) + } + + onbeforeupdate() { + // If needsRebuild returns true, mithril will diff and redraw the vnode as usual. Otherwise, it will skip this redraw cycle. + // In this example, this means that this component and its children will only be redrawn when extra content is toggled. + return this.subtree.needsRebuild(); + } + + view(vnode) { + return
+ +

Hello World!{this.showContent ? ' Extra Content!' : ''}

+
; + } +} +``` + +#### attrs() method + +Previously, some components would have an attrs() method, which provided an extensible way to provide attrs to the top-level child vnode returned by `view()`. For instance, + +```js +class CustomComponent extends Component { + view() { + return

Hello World!

; + } + + attrs() { + return { + className: 'SomeClass', + onclick: () => console.log('click'), + }; + } +} +``` + +Since `this.attrs` is now used for attrs passed in from parent components, `attrs` methods have been renamed to `elementAttrs`. + +#### Children and .component + +Previously, an element could be created with child elements by passing those in as the `children` prop: + +```js +Button.component({ + className: 'Button Button--primary', + children: 'Button Text' +}); +``` + +This will no longer work, and will actually result in errors. Instead, the 2nd argument of the `component` method should be used: + +```js +Button.component({ + className: 'Button Button--primary' +}, 'Button Text'); +``` + +Children can still be passed in through JSX: + +```js + +``` + +#### Tag attr + +Because mithril uses 'tag' to indicate the actual html tag (or component class) used for a vnode, you can no longer pass `tag` as an attr to components extending Flarum's `Component` helper class. The best workaround here is to just use another name for this attr. + +#### affixSidebar + +The `affixSidebar` util has been removed. Instead, if you want to affix a sidebar, wrap the sidebar code in an `AffixedSidebar` component. For instance, + +```js +class OldWay extends Component { + view() { + return
+
+
+ +
Actual Page Content
+
+
+
; + } +} + +class NewWay extends Component { + view() { + return
+
+
+ + + +
Actual Page Content
+
+
+
; + } +} +``` + +#### Fragment + +**Warning: For Advanced Use Only** + +In some rare cases, we want to have extremely fine grained control over the rendering and display of some significant chunks of the DOM. These are attached with `m.render`, and do not experience automated redraws. Current use cases in core and bundled extensions are: + +- The "Reply" button that shows up when selecting text in a post +- The mentions autocomplete menu that shows up when typing +- The emoji autocomplete menu that shows up when typing + +For this purpose, we provide a helper class (`common/Fragment`), of which you can create an instance, call methods, and render via `m.render(DOM_ROOT, fragmentInstance.render())`. The main benefit of using the helper class is that it allows you to use lifecycle methods, and to access the underlying DOM via `this.$()`, like you would be able to do with a component. + +This should only be used when absolutely necessary. If you are unsure, you probably don't need it. If the goal is to not store component instances, the "state pattern" as described above is preferable. + +### Required Frontend Changes Recap + +Each of these changes has been explained above, this is just a recap of major changes for your convenience. + +- Component Methods: + - `view()` -> `view(vnode)` + - Lifecycle + - `init()` -> `oninit(vnode)` + - `config()` -> Lifecycle hooks `oncreate(vnode)` / `onupdate(vnode)` + - `context.onunload()` -> `onremove()` + - `SubtreeRetainer` -> `onbeforeupdate()` + - if present, `attrs()` method needs to be renamed -> convention `elementAttrs()` + - building component with `MyComponent.component()` -> `children` is now second parameter instead of a named prop/attr (first argument) -> JSX preferred +- Routing + - `m.route()` -> `m.route.get()` + - `m.route(name)` -> `m.route.set(name)` + - register routes with page class, not instance + - special case when passing props + - `` -> `` +- AJAX + - `m.request({...})` -> `data:` key split up into `body:` and `params:` + - `m.deferred` -> native `Promise` +- Redrawing + - `m.redraw(true)` -> `m.redraw.sync()` + - `m.redraw.strategy('none')` -> `e.redraw = false` in event handler + - `m.lazyRedraw()` -> `m.redraw()` + +#### Deprecated changes + +For the following changes, we currently provide a backwards-compatibility layer. This will be removed in time for the stable release. The idea is to let you release a new version that's compatible with Beta 14 to your users as quickly as possible. When you have taken care of the changes above, you should be good to go. For the following changes, we have bought you time until the stable release. Considering you have to make changes anyway, why not do them now? + +- `this.props` -> `this.attrs` +- static `initProps()` -> static `initAttrs()` +- `m.prop` -> `flarum/utils/Stream` +- `m.withAttr` -> `flarum/utils/withAttr` +- `moment` -> `dayjs` + +## Backend (PHP) + +### New Features + +#### Extension Dependencies + +Some extensions are based on, or add features to, other extensions. Prior to this release, there was no way to ensure that those dependencies were enabled before the extension that builds on them. Now, you cannot enable an extension unless all of its dependencies are enabled, and you cannot disable an extension if there are other enabled extensions depending on it. + +So, how do we specify dependencies for an extension? Well, all you need to do is add them as composer dependencies to your extension's `composer.json`! For instance, if we have an extension that depends on Tags and Mentions, our `composer.json` will look like this: + +```json +{ + "name": "my/extension", + "description": "Cool New Extension", + "type": "flarum-extension", + "license": "MIT", + "require": { + "flarum/core": "^0.1.0-beta.14", + "flarum/tags": "^0.1.0-beta.14", // Will mark tags as a dependency + "flarum/mentions": "^0.1.0-beta.14", // Will mark mentions as a dependency + } + // other config +} +``` + +#### View Extender + +Previously, when extensions needed to register Laravel Blade views, they could inject a view factory in `extend.php` and call it's `addNamespace` method. For instance, + +```php +// extend.php +use Illuminate\Contracts\View\Factory; + +return [ + function (Factory $view) { + $view->addNamespace(NAME, RELATIVE PATH); + } +] +``` + +This should NOT be used, as it will break views for all extensions that boot after yours. Instead, the `View` extender should be used: + +```php +// extend.php +use Flarum\Extend\View; + +return [ + (new View)->namespace(NAME, RELATIVE PATH); +] +``` + +#### Application and Container + +Although Flarum uses multiple components of the Laravel framework, it is not a pure Laravel system. In beta 14, the `Flarum\Foundation\Application` class no longer implements `Illuminate\Contracts\Foundation\Application`, and no longer inherits `Illuminate\Container\Container`. Several things to note: + +- The `app` helper now points to an instance of `Illuminate\Container\Container`, not `Flarum\Foundation\Application`. You might need to resolve things through the container before using them: for instance, `app()->url()` will no longer work; you'll need to resolve or inject an instance of `Flarum\Foundation\Config` and use that. +- Injected or resolved instances of `Flarum\Foundation\Application` can no longer resolve things through container methods. `Illuminate\Container\Container` should be used instead. +- Not all public members of `Illuminate\Contracts\Foundation\Application` are available through `Flarum\Foundation\Application`. Please refer to our [API docs on `Flarum\Foundation\Application`](https://api.docs.flarum.org/php/master/flarum/foundation/application) for more information. + +#### Other Changes + +- We are now using Laravel 6. Please see [Laravel's upgrade guide](https://laravel.com/docs/6.x/upgrade) for more information. Please note that we do not use all of Laravel. +- Optional params in url generator now work. For instance, the url generator can now properly generate links to posts in discussions. +- A User Extender has been added, which replaces the deprecated `PrepareUserGroups` and `GetDisplayName` events. +- Error handler middleware can now be manipulated by the middleware extender through the `add`, `remove`, `replace`, etc methods, just like any other middleware. +- `Flarum/Foundation/Config` and `Flarum/Foundation/Paths` can now be injected where needed; previously their data was accessible through `Flarum/Foundation/Application`. + +### Deprecations + +- `url` provided in `config.php` is now an array, accessible via `$config->url()`, for an instance of `Config` - [PR](https://github.com/flarum/core/pull/2271#discussion_r475930358) +- AssertPermissionTrait has been deprecated - [Issue](https://github.com/flarum/core/issues/1320) +- Global path helpers and path methods of `Application` have been deprecated, the injectable `Paths` class should be used instead - [PR](https://github.com/flarum/core/pull/2155) +- `Flarum\User\Event\GetDisplayName` has been deprecated, the `displayNameDriver` method of the `User` extender should be used instead - [PR](https://github.com/flarum/core/pull/2174) + +### Removals + +- Do NOT use the old closure notation for configuring view namespaces. This will break all extensions that boot after your extension. The `View` extender MUST be used instead. +- app()->url() will no longer work: [`Flarum\Http\UrlGenerator`](routes.md) should be injected and used instead. An instance of `Flarum\Http\UrlGenerator` is available in `blade.php` templates via `$url`. +- As a part of the Laravel 6 upgrade, the [`array_` and `str_` helpers](https://laravel.com/docs/6.x/upgrade#helpers) have been removed. +- The Laravel translator interface has been removed; the Symfony translator interface should be used instead: `Symfony\Component\Translation\TranslatorInterface` +- The Mandrill mail driver is no longer provided in Laravel 6, and has been removed. +- The following events deprecated in Beta 13 [have been removed](https://github.com/flarum/core/commit/7d1ef9d89161363d1c8dea19cf8aebb30136e9e3#diff-238957b67e42d4e977398cd048c51c73): + - `AbstractConfigureRoutes` + - `ConfigureApiRoutes` - Use the `Routes` extender instead + - `ConfigureForumRoutes` - Use the `Frontend` or `Routes` extenders instead + - `ConfigureLocales` - Use the `LanguagePack` extender instead + - `ConfigureModelDates` - Use the `Model` extender instead + - `ConfigureModelDefaultAttributes` - Use the `Model` extender instead + - `GetModelRelationship` - Use the `Model` extender instead + - `Console\Event\Configuring` - Use the `Console` extender instead + - `BioChanged` - User bio has not been a core feature for several releases diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md new file mode 100644 index 000000000..c815ca9c2 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md @@ -0,0 +1,60 @@ +# Updating For Beta 15 + +Beta 15 features multiple new extenders, a total redesign of the admin dashboard, and several other interesting new features for extensions. As before, we have done our best to provide backwards compatibility layers, and we recommend switching away from deprecated systems as soon as possible to make your extensions more stable. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## New Features / Deprecations + +### Extenders + +- `Flarum\Api\Event\WillGetData` and `Flarum\Api\Event\WillSerializeData` have been deprecated, the `ApiController` extender should be used instead +- `Flarum\Api\Event\Serializing` and `Flarum\Event\GetApiRelationship` have been deprecated, the `ApiSerializer` extender should be used instead +- `Flarum\Formatter\Event\Parsing` has been deprecated, the `parse` method of the `Formatter` extender should be used instead +- `Flarum\Formatter\Event\Rendering` has been deprecated, the `render` method of the `Formatter` extender should be used instead +- `Flarum\Notification\Event\Sending` has been deprecated, the `driver` method of the `Notification` extender should be used instead + - Please note that the new notification driver system is not an exact analogue of the old `Sending` event, as it can only add new drivers, not change the functionality of the default notification bell alert driver. If your extension needs to modify **how** or **to whom** notifications are sent, you may need to replace `Flarum\Notification\NotificationSyncer` on the service provider level +- `Flarum\Event\ConfigureNotificationTypes` has been deprecated, the `type` method of the `Notification` extender should be used instead +- `Flarum\Event\ConfigurePostTypes` has been deprecated, the `type` method of the `Post` extender should be used instead +- `Flarum\Post\Event\CheckingForFlooding` has been deprecated, as well as `Flarum\Post\Floodgate`. They have been replaced with a middleware-based throttling system that applies to ALL requests to /api/*, and can be configured via the `ThrottleApi` extender. Please see our [api-throttling](api-throttling.md) documentation for more information. +- `Flarum\Event\ConfigureUserPreferences` has been deprecated, the `registerPreference` method of the `User` extender should be used instead +- `Flarum\Foundation\Event\Validating` has been deprecated, the `configure` method of the `Validator` extender should be used instead + +- The Policy system has been reworked a bit to be more intuitive. Previously, policies contained both actual policies, which determine whether a user can perform some ability, and model visibility scopers, which allowed efficient restriction of queries to only items that users have access to. See the [authorization documentation](authorization.md) for more information on how to use the new systems. Now: + - `Flarum\Event\ScopeModelVisibility` has been deprecated. New scopers can be registered via the `ModelVisibility` extender, and any `Eloquent\Builder` query can be scoped by calling the `whereVisibleTo` method on it, with the ability in question as an optional 2nd argument (defaults to `view`). + - `Flarum\Event\GetPermission` has been deprecated. Policies can be registered via the `Policy` extender. `Flarum\User\User::can` has not changed. Please note that the new policies must return one of `$this->allow()`, `$this->deny()`, `$this->forceAllow()`, `$this->forceDeny()`, not a boolean. + +- A `ModelUrl` extender has been added, allowing new slug drivers to be registered. This accompanies Flarum's new slug driving system, which allows for extensions to define custom slugging strategies for sluggable models. The extender supports sluggable models outside of Flarum core. Please see our [model slugging](slugging.md) documentation for more information. +- A `Settings` extender has been added, whose `serializeToForum` method makes it easy to serialize a setting to the forum. +- A `ServiceProvider` extender has been added. This should be used with extreme caution for advanced use cases only, where there is no alternative. Please note that the service provider layer is not considered public API, and is liable to change at any time, without notice. + +### Admin UX Redesign + +The admin dashboard has been completely redesigned, with a focus on providing navbar pages for each extension. The API for extensions to register settings, permissions, and custom pages has also been greatly simplified. You can also now update your extension's `composer.json` to provide links for funding, support, website, etc that will show up on your extension's admin page. Please see [our Admin JS documentation](admin.md) for more information on how to use the new system. + +### Other New Features + +- On the backend, the route name is now available via `$request->getAttribute('routeName')` for controllers, and for middleware that run after `Flarum\Http\Middleware\ResolveRoute.php`. +- `Flarum\Api\Controller\UploadImageController.php` can now be used as a base class for controllers that upload images (like for the logo and favicon). +- Automatic browser scroll restoration can now be disabled for individual pages [see our frontend page documentation for more info](frontend-pages.md). + +## Breaking Changes + +- The following deprecated frontend BC layers were removed: + - `momentjs` no longer works as an alias for `dayjs` + - `this.props` and `this.initProps` no longer alias `this.attrs` and `this.initAttrs` for the `Component` base class + - `m.withAttr` and `m.stream` no longer alias `flarum/utils/withAttr` and `flarum/utils/Stream` + - `app.cache.discussionList` has been removed + - `this.content` and `this.editor` have been removed from `ComposerBody` + - `this.component`, `this.content`, and `this.value` have been removed from `ComposerState` +- The following deprecated backend BC layers were removed: + - The `publicPath`, `storagePath`, and `vendorPath` methods of `Flarum\Foundation\Application` have been removed + - The `base_path`, `public_path`, and `storage_path` global helpers have been removed + - The `getEmailSubject` method of `Flarum\Notification\MailableInterface` MUST now take a translator instance as an argument + - `Flarum\User\AssertPermissionTrait` has been removed, the analogous methods on `Flarum\User\User` should be used instead + - The `Flarum\Event\PrepareUserGroups` event has been removed, use the `User` extender instead + - The `Flarum\User\Event\GetDisplayName` event has been removed, use the display name driver feature of the `User` extender instead diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md new file mode 100644 index 000000000..dbbc0cc5d --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md @@ -0,0 +1,138 @@ +# Updating For Beta 16 + +Beta 16 finalizes the PHP extender API, introduces a testing library and JS typings, switches to using namespaces for JS imports, increases extension dependency robustness, and allows overriding routes, among other features. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Frontend + +- A new editor driver abstraction has been introduced, which allows extensions to override the default textarea-based editor with more advanced solutions. +- The `TextEditor` and `TextEditorButton` components, as well as the `BasicEditorDriver` util (which replaces `SuperTextarea`) have been moved from `forum` to `common`. +- The `forum`, `admin`, and `common` namespaces should be used when importing. So instead of `import Component from 'flarum/Component'`, use `import Component from 'flarum/common/Component`. Support for the old import styles will be deprecated through the stable release, and removed with Flarum 2.0. +- A typing library has been released to support editor autocomplete for frontend development, and can be installed in your dev environment via `npm install --save-dev flarum@0.1.0-beta.16`. +- Extension categories have been simplified down to `feature`, `theme`, and `language`. + +## Backend + +### Extenders + +- All extenders that support callbacks/closures now support global functions like `'boolval'` and array-type functions like `[ClassName::class, 'methodName']`. +- The `Settings` extender's `serializeToFrontend` method now supports a default value as the 4th argument. +- The `Event` extender now supports registering subscribers for multiple events at once via a `subscribe` method. +- The `Notification` extender now has a `beforeSending` method, which allows you to adjust the list of recipients before a notification is sent. +- The `mutate` method of `ApiSerializer` has been deprecated, and renamed to `attributes`. +- `remove` methods on the `Route` and `Frontend` extenders can be used to remove (and then replace) routes. +- A `ModelPrivate` extender replaces the `GetModelIsPrivate` event, which has been deprecated. +- Methods on the `Auth` extender replace the `CheckingPassword` event, which has been deprecated. +- All search-related events are now deprecated in favor of the `SimpleFlarumSearch` and `Filter` extenders; this is explained in more detail below. + +### Laravel and Symfony + +Beta 16 upgrades from v6.x to v8.x of Laravel components and v4 to v5 of Symfony components. Please see the respective upgrade guides of each for changes you might need to make to your extensions. The most applicable change is the deprecation of `Symfony\Component\Translation\TranslatorInterface` in favor of `Symfony\Contracts\Translation\TranslatorInterface`. The former will be removed in beta 17. + +### Helper Functions + +The remaining `app` and `event` global helper functions have been deprecated. `app` has been replaced with `resolve`, which takes the name of a container binding and resolves it through the container. + +Since some Flarum extensions use Laravel libraries that assume some global helpers exist, we've recreated some commonly used helpers in the [flarum/laravel-helpers](https://github.com/flarum/laravel-helpers) package. These helpers should NOT be used directly in Flarum extension code; they are available so that Laravel-based libraries that expect them to exist don't malfunction. + +### Search Changes + +As part of our ongoing efforts to make Flarum's search system more flexible, we've made several refactors in beta 16. Most notably, filtering and searching are now treated as different mechanisms, and have separate pipelines and extenders. Essentially, if a query has a `filter[q]` query param, it will be treated as a search, and all other filter params will be ignored. Otherwise, it will be handled by the filtering system. This will eventually allow searches to be handled by alternative drivers (provided by extensions), such as ElasticSearch, without impacting filtering (e.g. loading recent discussions). Classes common to both systems have been moved to a `Query` namespace. + +Core's filtering and default search (named SimpleFlarumSearch) implementations are quite similar, as both are powered by the database. `List` API controllers call the `search` / `filter` methods on a resource-specific subclass of `Flarum\Search\AbstractSearcher` or `Flarum\Filter\AbstractFilterer`. Arguments are an instance of `Flarum\Query\QueryCriteria`, as well as sort, offset, and limit information. Both systems return an instance of `Flarum\Query\QueryResults`, which is effectively a wrapper around a collection of Eloquent models. + +The default systems are also somewhat similar in their implementation. `Filterer`s apply Filters (implementing `Flarum\Filter\FilterInterface`) based on query params in the form `filter[FILTER_KEY] = FILTER_VALUE` (or `filter[-FILTER_KEY] = FILTER_VALUE` for negated filters). SimpleFlarumSearch's `Searcher`s split the `filter[q]` param by spaces into "terms", apply Gambits (implementing `Flarum\Search\GambitInterface`) that match the terms, and then apply a "Fulltext Gambit" to search based on any "terms" that don't match an auxiliary gambit. Both systems then apply sorting, an offset, and a result count limit, and allow extensions to modify the query result via `searchMutators` or `filterMutators`. + +Extensions add gambits and search mutators and set fulltext gambits for `Searcher` classes via the `SimpleFlarumSearch` extender. They can add filters and filter mutators to `Filterer` classes via the `Filter` extender. + +With regards to upgrading, please note the following: + +- Search mutations registered by listening to the `Searching` events for discussions and users will be applied as to searches during the search mutation step via a temporary BC layer. They WILL NOT be applied to filters. This is a breaking change. These events have been deprecated. +- Search gambits registered by listening to the `ConfigureUserGambits` and `ConfigureDiscussionGambits` events will be applied to searcher via a temporary BC layer. They WILL NOT be applied to filters. This is a breaking change. These events have been deprecated. +- Post filters registered by listening to the `ConfigurePostsQuery` events will be applied to post filters via a temporary BC layer. That event has been deprecated. + +### Testing Library + +The `flarum/testing` package provides utils for PHPUnit-powered automated backend tests. See the [testing documentation](testing.md) for more info. + +### Optional Dependencies + +Beta 15 introduced "extension dependencies", which require any extensions listed in your extension's `composer.json`'s `require` section to be enabled before your extension can be enabled. + +With beta 16, you can specify "optional dependencies" by listing their composer package names as an array in your extension's `extra.flarum-extension.optional-dependencies`. Any enabled optional dependencies will be booted before your extension, but aren't required for your extension to be enabled. + +### Access Token and Authentication Changes + +#### Extension API changes + +The signature to various method related to authentication have been changed to take `$token` as parameter instead of `$userId`. Other changes are the result of the move from `$lifetime` to `$type` + +- `Flarum\Http\AccessToken::generate($userId)` no longer accepts `$lifetime` as a second parameter. Parameter has been kept for backward compatibility but has no effect. It will be removed in beta 17. +- `Flarum\Http\RememberAccessToken::generate($userId)` should be used to create remember access tokens. +- `Flarum\Http\DeveloperAccessToken::generate($userId)` should be used to create developer access tokens (don't expire). +- `Flarum\Http\SessionAccessToken::generate()` can be used as an alias to `Flarum\Http\AccessToken::generate()`. We might deprecate `AccessToken::generate()` in the future. +- `Flarum\Http\Rememberer::remember(ResponseInterface $response, AccessToken $token)`: passing an `AccessToken` has been deprecated. Pass an instance of `RememberAccessToken` instead. As a temporary compatibility layer, passing any other type of token will convert it into a remember token. In beta 17 the method signature will change to accept only `RememberAccessToken`. +- `Flarum\Http\Rememberer::rememberUser()` has been deprecated. Instead you should create/retrieve a token manually with `RememberAccessToken::generate()` and pass it to `Rememberer::remember()` +- `Flarum\Http\SessionAuthenticator::logIn(Session $session, $userId)` second parameter has been deprecated and is replaced with `$token`. Backward compatibility is kept. In beta 17, the second parameter method signature will change to `AccessToken $token`. +- `AccessToken::generate()` now saves the model to the database before returning it. +- `AccessToken::find($id)` or `::findOrFail($id)` can no longer be used to find a token, because the primary key was changed from `token` to `id`. Instead you can use `AccessToken::findValid($tokenString)` +- It's recommended to use `AccessToken::findValid($tokenString): AccessToken` or `AccessToken::whereValid(): Illuminate\Database\Eloquent\Builder` to find a token. This will automatically scope the request to only return valid tokens. On forums with low activity this increases the security since the automatic deletion of outdated tokens only happens every 50 requests on average. + +#### Symfony session changes + +If you are directly accessing or manipulating the Symfony session object, the following changes have been made: + +- `user_id` attribute is no longer used. `access_token` has been added as a replacement. It's a string that maps to the `token` column of the `access_tokens` database table. + +To retrieve the current user from inside a Flarum extension, the ideal solution which was already present in Flarum is to use `$request->getAttribute('actor')` which returns a `User` instance (which might be `Guest`) + +To retrieve the token instance from Flarum, you can use `Flarum\Http\AccessToken::findValid($tokenString)` + +To retrieve the user data from a non-Flarum application, you'll need to make an additional database request to retrieve the token. The user ID is present as `user_id` on the `access_tokens` table. + +#### Token creation changes + +The `lifetime` property of access tokens has been removed. Tokens are now either `session` tokens with 1h lifetime after last activity, or `session_remember` tokens with 5 years lifetime after last activity. + +The `remember` parameter that was previously available on the `POST /login` endpoint has been made available on `POST /api/token`. It doesn't return the remember cookie itself, but the token returned can be used as a remember cookie. + +The `lifetime` parameter of `POST /api/token` has been deprecated and will be removed in Flarum beta 17. Partial backward compatibility has been provided where a `lifetime` value longer than 3600 seconds is interpreted like `remember=1`. Values lower than 3600 seconds result in a normal non-remember token. + +New `developer` tokens that don't expire have been introduced, however they cannot be currently created through the REST API. Developers can create developer tokens from an extension using `Flarum\Http\DeveloperAccessToken::generate($userId)`. + +If you manually created tokens in the database from outside Flarum, the `type` column is now required and must contain `session`, `session_remember` or `developer`. Tokens of unrecognized type cannot be used to authenticate, but won't be deleted by the garbage collector either. In a future version extensions will be able to register custom access token types. + +#### Token usage changes + +A [security issue in Flarum](https://github.com/flarum/core/issues/2075) previously caused all tokens to never expire. This had limited security impact due to tokens being long unique characters. However custom integrations that saved a token in an external database for later use might find the tokens no longer working if they were not used recently. + +If you use short-lived access tokens for any purpose, take note of the expiration time of 1h. The expiration is based on the time of last usage, so it will remain valid as long as it continues to be used. + +Due to the large amount of expired tokens accumulated in the database and the fact most tokens weren't ever used more than once during the login process, we have made the choice to delete all access tokens a lifetime of 3600 seconds as part of the migration, All remaining tokens have been converted to `session_remember` tokens. + +#### Remember cookie + +The remember cookie still works like before, but a few changes have been made that could break unusual implementations. + +Now only access tokens created with `remember` option can be used as remember cookie. Any other type of token will be ignored. This means if you create a token with `POST /api/token` and then place it in the cookie manually, make sure you set `remember=1` when creating the token. + +#### Web session expiration + +In previous versions of Flarum, a session could be kept alive forever until the Symfony session files were deleted from disk. + +Now sessions are linked to access tokens. A token being deleted or expiring will automatically end the linked web session. + +A token linked to a web session will now be automatically deleted from the database when the user clicks logout. This prevents any stolen token from being re-used, but it could break custom integration that previously used a single access token in both a web session and something else. + +### Miscellaneous + +- The IP address is now available in requests via `$request->getAttribute('ipAddress')` +- Policies can now return `true` and `false` as aliases for `$this->allow()` and `$this->deny()`, respectively. +- The `user.edit` permission has been split into `user.editGroups`, `user.editCredentials` (for email, username, and password), and `user.edit` (for other attributes). +- There are now permissions (`bypassTagCounts`) that allow users to bypass tag count requirements. +- Flarum now supports PHP 7.3 - PHP 8.0, with support for PHP 7.2 officially dropped. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md new file mode 100644 index 000000000..3a8f9c6e9 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md @@ -0,0 +1,114 @@ +# Updating For Beta 8 + +All extensions will need to be refactored in order to work with beta 8. Here are the main things you will need to do in order to make your extension compatible. + +:::caution + +This guide is not comprehensive. You may encounter some changes we haven't documented. If you need help, start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## PHP Namespaces + +Beta 8 comes with large changes to the overall structure of the PHP backend. You will need to look through [this list](https://discuss.flarum.org/d/6572-help-us-namespace-changes) of namespace changes and make changes to your extension accordingly. + +[This script](https://gist.github.com/tobyzerner/55e7c05c95404e5efab3a9e43799d375) can help you to automate most of the namespace changes. Of course, you should still test your extension after running the script as it may miss something. + +## Database Naming + +Many database columns and JSON:API attributes have been renamed to conform to a [convention](/contributing.md#database). You will need to update any instances where your extension interacts with core data. You can see the changes in [#1344](https://github.com/flarum/core/pull/1344/files). + +## Extenders + +Beta 8 introduces a new concept called **extenders** that replace the most common event listeners. You can learn more about how they work in the [updated extension docs](start.md#extenders). + +`bootstrap.php` has been renamed to `extend.php` and returns an array of extender instances and functions: + +```php +use Flarum\Extend; + +return [ + (new Extend\Frontend('forum')) + ->js(__DIR__.'/js/dist/forum.js') + ->css(__DIR__.'/less/forum.less') + ->route('/t/{slug}', 'tag') + ->route('/tags', 'tags'), + + function (Dispatcher $events) { + $events->subscribe(Listener\AddForumTagsRelationship::class); + } +] +``` + +If you're listening for any of the following events, you'll need to update your code to use an extender instead. See the relevant docs for more information. + +| Event | Extender | +| ------------------------------------- | --------------------------- | +| `Flarum\Event\ConfigureFormatter`* | `Flarum\Extend\Formatter` | +| `Flarum\Event\ConfigureWebApp`* | `Flarum\Extend\Frontend` | +| `Flarum\Event\ConfigureClientView`* | `Flarum\Extend\Frontend` | +| `Flarum\Event\ConfigureLocales` | `Flarum\Extend\Locales` | +| `Flarum\Event\ConfigureApiRoutes` | `Flarum\Extend\Routes` | +| `Flarum\Event\ConfigureForumRoutes` | `Flarum\Extend\Routes` | + +_\* class no longer exists_ + +## JavaScript Tooling + +Previously Flarum and its extensions used a custom Gulp workflow to compile ES6 source code into something that browsers could understand. Beta 8 switches to a more conventional approach with Webpack. + +You will need to tweak the structure of your extension's `js` directory. Currently, your JS file hierarchy looks something like the following: + +``` +js +├── admin +│ ├── src +│ │ └── main.js +│ ├── dist +│ │ └── extension.js +│ ├── Gulpfile.js +│ └── package.json +└── forum + ├── src + │ └── main.js + ├── dist + │ └── extension.js + ├── Gulpfile.js + └── package.json +``` + +You'll need to make the following changes: + +1. Update `package.json` and create `webpack.config.js`, `forum.js`, and `admin.js` files using [these templates](frontend.md#transpilation). + +2. Inside your `admin` and `forum` *folders*, delete `Gulpfile.js`, `package.json`, and `dist`. Then inside each `src` folder, rename `main.js` to `index.js`. Now move all of the `src` files outside of `src` folder and delete it. + +3. In the root `js` folder create a folder called `src` and move your `admin` and `forum` *folders* into it. + +4. While still in your root `js` folder, run `npm install` and then `npm run build` to build the new JS dist files. + +If everything went right, your folder structure should look something like this: + +``` +js +├── src +│ ├── admin +│ │ └── index.js +│ └── forum +│ └── index.js +├── dist +│ ├── admin.js +│ ├── admin.js.map +│ ├── forum.js +│ └── forum.js.map +├── admin.js +├── forum.js +├── package.json +└── webpack.config.js +``` + +Take a look at the [bundled extensions](https://github.com/flarum) for more examples. + +## Font Awesome Icons + +Beta 8 upgrades to Font Awesome 5, in which icon class names have changed. The `flarum/helpers/icon` helper now requires the **full Font Awesome icon class names** to be passed, eg. `fas fa-bolt`. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/views.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/views.md new file mode 100644 index 000000000..fc4a75a86 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extend/views.md @@ -0,0 +1,63 @@ +# Views and Blade + +Although the Flarum UI you know and love is powered by our [Mithril frontend](frontend), server-side generated templates are still used throughout Flarum. Most notably, the HTML skeleton of the forum, which includes various SEO meta tags, as well as the no-js view of the forum, is implemented through the Views and Blade systems. + +[Blade](https://laravel.com/docs/8.x/blade) is Laravel's templating engine, which allows you to conveniently generate HTML (or other static content) from PHP. It's the same idea as [Jinja](https://jinja.palletsprojects.com/en/3.0.x/) or [EJS](https://ejs.co/). [Views](https://laravel.com/docs/8.x/views) are Laravel's system for organizing/registering Blade templates, and also includes utilities for rendering them and providing them with variables. + +For our purposes, views are directories containing `.blade.php` template files (possibly contained in subdirectories). + +## Adding Views + +You will need to tell the view factory where it can find your extension's view files by adding a `View` extender to `extend.php`: + +```php +use Flarum\Extend; +use Illuminate\Contracts\View\Factory; + +return [ + (new Extend\View) + ->namespace('acme.hello-world', __DIR__.'/views'), +]; +``` + + +## Blade Templates + +To learn about the syntax for Blade templates, read [Laravel's documentation](https://laravel.com/docs/8.x/blade). + +Once you've set up your views, you can render them to strings: + +```php +// Here, $view is of type `Illuminate\Contracts\View\Factory` +$renderedString = $view->make('acme.hello-world::greeting')->render(); + +// You can also pass variables to the view: +$renderedString = $view->make('acme.hello-world::greeting', ['varName' => true])->render(); +``` + +You can obtain the view factory instance through dependency injection. + +The format is `"VIEW_NAMESPACE::VIEW_NAME"`. If the view folder is organized as subdirectories, replace `/` with `.` in the pack. So if you have a file at `"forum/error.blade.php"` in a namespace called `"custom-views"`, you would use `"custom-views::forum.error"`. + +Note that all Blade templates rendered this way automatically have access to the following variables: + +- `$url`: a [URL generator](routes#generating-urls) instance. +- `$translator`: a [Translator](i18n#server-side-translation) instance. +- `$settings`: a [SettingsInterface](settings) instance. +- `$slugManager`: a [SlugManager](slugging) instance. + +Additionally, templates used by [content logic](routes#content) have access to `$forum`, which represents the [Forum API Document's attributes](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Serializer/ForumSerializer.php#L19). + +## Overriding Views + +If you want to override templates added by core or extensions, set up a view folder structure matching the one you are trying to override, containing just the files you are trying to override. Then use the `View` extender's `extendNamespace` method: + +```php +use Flarum\Extend; +use Illuminate\Contracts\View\Factory; + +return [ + (new Extend\View) + ->extendNamespace('acme.hello-world', __DIR__.'/override_views'); +]; +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extenders.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extenders.md new file mode 100644 index 000000000..9d1c686d3 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extenders.md @@ -0,0 +1,23 @@ +# Lokale Extender + +Wenn du Anpassungen an deiner Seite vornehmen möchtest, ohne eine ganze Erweiterung zu erstellen, kannst du dies mit **lokalen Extendern** tun. Jede Flarum-Installation wird mit einer `extend.php`-Datei geliefert, in der du Extender-Instanzen hinzufügen kannst, genau wie bei einer vollständigen Erweiterung. + +In unserer [Erweiterungsdokumentation](extend/start.md) findest du weitere Informationen über Extender (und auch ein [Beispiel für einen lokalen Extender](extend/start.md#hello-world)). + +Wenn du neue Dateien erstellen musst (wenn du eine benutzerdefinierte Klasse hinzufügst, die für Extender importiert werden soll), musst du deine composer.json ein wenig anpassen. Füge Folgendes hinzu: + +```json +"autoload": { + "psr-4": { + "App\\": "app/" + } +}, +``` + +Jetzt kannst du neue PHP-Dateien in einem `App`-Unterverzeichnis erstellen, indem du den `App\...`-Namensraum benutzt. + +:::tip Lokale Extender vs. Erweiterungen + +Lokale Extender können für kleine Anpassungen gut sein, aber wenn Sie umfangreiche Anpassungen benötigen, ist eine Erweiterung möglicherweise die bessere Wahl: Eine separate Codebasis, eine sauberere Handhabung vieler Dateien, Werkzeuge für Entwickler und die Möglichkeit, den Quellcode zu teilen, sind große Vorteile. + +::: diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/extensions.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extensions.md new file mode 100644 index 000000000..c99747d2b --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/extensions.md @@ -0,0 +1,118 @@ +# Erweiterungen + +Flarum ist minimalistisch, aber auch sehr erweiterbar. Tatsächlich sind die meisten Funktionen, die mit Flarum geliefert werden, tatsächlich Erweiterungen! + +Dieser Ansatz macht Flarum extrem anpassbar: Du kannst alle Funktionen deaktivieren, die Du nicht benötigst, und andere Erweiterungen installieren, um dein Forum perfekt für deine Community zu machen. + +Weitere Informationen zu Flarums Philosophie darüber, welche Funktionen wir im Kern enthalten, oder wenn Du deine eigene Erweiterung erstellen möchtest, findest Du in unserer [Erweiterungsdokumentation](extend/README.md). Dieser Artikel konzentriert sich auf die Verwaltung von Erweiterungen aus der Perspektive eines Forum-Administrators. + +## Extension Manager + +The extension manager is an extension that comes bundled with Flarum when installed via an archive. It provides a graphical interface for installing and updating both extensions and Flarum itself. + +If you do not have the extension manager installed and you wish to install it, you can do so by running the following command in your Flarum directory: + +```bash +composer require flarum/extension-manager:"*" +``` + +:::warning + +The extension manager allows an admin user to install any composer package. Only install the extension manager if you trust all of your forum admins with such permissions. + +::: + +![extension manager admin page](https://github.com/flarum/docs/assets/20267363/d0e1f7a5-e194-4acd-af63-7b8ddd95c26b) + + +## Erweiterungen finden + +Flarum verfügt über ein breites Ökosystem von Erweiterungen, von denen die meisten Open Source und kostenlos sind. Um neue und tolle Erweiterungen zu finden, besuche das [Extensions](https://discuss.flarum.org/t/extensions)-Tag in Flarums Community-Foren. Die inoffizielle [Extiverse Erweiterungsdatenbank](https://extiverse.com/) ist ebenfalls eine großartige Ressource. + +## Erweiterungen installieren + +### Through the interface + +Using the extension manager extension, you can install extensions directly from the admin dashboard. Once you have browsed the list of available extensions from the links above, and found one you want to install, you can install it by entering the extension's composer package name into the extension manager's installation input. + +![Installing an extension](/en/img/install-extension.png) + +### Through the command line + +Genau wie Flarum werden Erweiterungen über [Composer](https://getcomposer.org) mit SSH installiert. So installierst Du eine typische Erweiterung: + +1. `cd` in dein Flarumverzeichnis. Dieses Verzeichnis sollte `composer.json`, `flarum`-Dateien und ein `storage`-Verzeichnis (unter anderem) enthalten. Du kannst Verzeichnisinhalte über `ls -la` überprüfen. +2. Führe `composer require COMPOSER_PACKAGE_NAME:*` aus. Dies sollte durch die Dokumentation der Erweiterung bereitgestellt werden. + +## Aktualisieren von Erweiterungen + +### Through the interface + +Using the extension manager extension, you can update extensions directly from the admin dashboard. You can run a check for updates by clicking the "Check for updates" button in the extension manager. If there are updates available, you can update all extensions by clicking the "Global update" button. Or, you can update individual extensions by clicking the "Update" button next to the extension you want to update. + +![Updating an extension](/en/img/update-extension.png) + +### Through the command line + +Anweisungen der Erweiterungsentwickler befolgen. Wenn Du `*` als Versionszeichenfolge für Erweiterungen verwendest ([wie empfohlen](composer.md)), sollten all deine Erweiterungen aktualisiert werden, indem Du die Befehle ausführst, die in der [Flarum-Upgrade-Anleitung](update.md) aufgeführt sind. + +## Erweiterungen deinstallieren + +### Through the interface + +Using the extension manager extension, you can uninstall extensions directly from the admin dashboard. You can uninstall an extension by clicking the "Uninstall" button next to the extension you want to uninstall inside the extension's page. + +![Uninstalling an extension](/en/img/uninstall-extension.png) + +### Through the command line + +Ähnlich wie bei der Installation, um eine Erweiterung zu entfernen: + +0. Wenn Du alle von der Erweiterung erstellten Datenbanktabellen entfernen möchtest, klicke im Admin-Dashboard auf die Schaltfläche „Löschen“. Weitere Informationen findest Du [unten](#managing-extensions). +1. `cd` in dein Flarumverzeichnis. +2. Führe `composer remove COMPOSER_PACKAGE_NAME` aus. Dies sollte durch die Dokumentation der Erweiterung bereitgestellt werden. + +## Verwalten von Erweiterungen + +Each individual extension page of the admin dashboard provides a convenient way to manage the extension. Du kannst: + +- Enable or disable the extension. +- See the settings provided by the extension, and change them. +- Migrationen einer Erweiterung zurücksetzen, um alle vorgenommenen Datenbankänderungen zu entfernen (dies kann mit der Schaltfläche „Löschen“ erfolgen). Dadurch werden ALLE mit der Erweiterung verknüpften Daten entfernt und sind irreversibel. Dies sollte nur durchgeführt werden, wenn Du eine Erweiterung entfernst und nicht vorhast, sie erneut zu installieren. Es ist auch völlig optional. +- See the extension's README, if it has one. +- See the extension's version. +- Uninstall the extension if the extension manager is installed. + +## Configuring additional extension repository sources + +The extension manager uses `composer` under the hood, and as such, it looks for extension packages in the same places as `composer`. By default, this is [Packagist](https://packagist.org/). However, you can configure additional sources for the extension manager to look for extensions in. This is useful if you want to install an extension that is not available on Packagist. + +In the admin page of the extension manager, clicking the **Add Repository** button will open a modal where you can enter the name and URL of the repository you want to add. The name is just a label for the repository, and can be anything you want. The URL should be the URL of the repository which depends on the type of repository you want to add. + +### Adding a repository from a VCS + +If you want to add a repository from a VCS (e.g. GitHub, GitLab, BitBucket, etc), the URL should be the URL of the repository's VCS. For example, if you had a private GitHub repository at `https://github.com/acme/flarum-extension`, you would enter that URL into the URL field. If it is a private source, you will need to enter an authentication method through the **New authentication method** button. The token can be generated from your VCS provider's website, and the host should be the domain of the VCS provider (e.g. `github.com`). + +### Adding a composer repository + +Extiverse provides access to premium extensions. It is a good example of a composer repository. You would specify the URL as `https://flarum.org/composer/` and the name as `premium`. You would also need to enter an authentication method through the **New authentication method** button. The token can be generated from your Flarum account's [subscriptions](https://flarum.org/dashboard/subscriptions) page with the Instructions button. + +* Type: `HTTP Bearer` +* Host: `flarum.org` + +![Configure repositories](/en/img/config-repositories.png) + +:::info + +The configured repositories and auth methods will be active for both the command line and the admin dashboard. If you configure them from the command line however, you must not include the flag `--global`. + +::: + +## Installing Non-stable extensions + +If for whatever reason you want to install a non-stable extension (e.g. a beta, alpha or RC version) you must first update the **Minimum stability** setting to the wanted stability. + +* If you set it to Alpha, you will be able to install alpha, beta, RC (Release Candidate) and stable versions. +* If you set it to Beta, you will be able to install beta, RC and stable versions. +* If you set it to RC, you will be able to install RC and stable versions. +* If you set it to Stable, you will only be able to install stable versions. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/faq.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/faq.md new file mode 100644 index 000000000..6acbfc349 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/faq.md @@ -0,0 +1,35 @@ +# FAQ + +### Ist Flarum stabil? + +Ja! Nach 6 Jahren Entwicklung ist Flarum 1.0.0 endlich da. + +### Was kommt als nächstes nach Stable? + +Wir arbeiten noch an einer formalen Roadmap. Wir haben viele Pläne und Ideen und freuen uns darauf, einen gründlicheren Meilenstein mit der Community zu teilen. + +### Kann ich Geld spenden, um die Entwicklung zu beschleunigen? + +Alle Spenden werden dankbar angenommen. Du kannst auf [GitHub Sponsors](https://github.com/sponsors/flarum) oder [OpenCollective](https://opencollective.com/flarum) spenden. + +Spenden wirken sich jedoch nicht direkt auf die Entwicklungsgeschwindigkeit von Flarum aus. Wir ermutigen Benutzer auch, auf andere Weise beizutragen, z. B. [Code beisteuern](contributing.md), [Erweiterungen erstellen](/extend/README.md), Dokumentation schreiben, Flarum in andere Sprachen übersetzen, Hilfe und Unterstützung in den [Community-Foren leisten](https://discuss.flarum.org/)... Und einfach eine allgemeine positive Energie in der Community sein! + +### Wird Flarum [Feature hier einfügen] haben? Wann? Warum nicht? + +Wir würden gerne unzählige Features und Erweiterungen für Flarum bauen, aber das Wichtigste zuerst: Unser Fokus liegt auf dem Wesentlichen und der Stabilität. + +### Warum habt ihr [Problem hier einfügen] noch nicht behoben? + +Auch hier lautet die Antwort „das Wichtigste zuerst“. Wenn wir ein Problem noch nicht behoben (oder ihm einen Meilenstein zugewiesen) haben, liegt das daran, dass wir an etwas anderem arbeiten, das genauso wichtig ist. Bitte habe Geduld; wir werden versuchen, es vor der Veröffentlichung zu erledigen. Oder wenn Du es eilig hast, kannst Du gerne selbst reparieren und [zum Projekt beitragen](contributing.md)! + +### Kann ich mein Forum zu Flarum migrieren? + +Wir bieten derzeit keine offiziellen Migrationsprogramme an, aber es existieren viele Community-Lösungen da draußen. Relativ bald werden wir damit beginnen, Tools zu entwickeln, um Daten aus anderer Forensoftware wie esoTalk, FluxBB, phpBB, Discourse und anderen zu importieren. + +### Wie trete ich dem Flarum-Team bei? + +> „Durch eine arkane und mühsame Tortur, die mystische Rituale, lebensbedrohliche Gefahren und Abenteuer in ferne Länder beinhaltet, in die viele gehen und nur wenige zurückkehren.“ ~ jordanjay29 + +Die wahre Antwort ist, dass wir unsere Community im Allgemeinen nach herausragenden Mitgliedern im Auge behalten, die gute Mitarbeiter abgeben würden. Ehrlich gesagt, für die meisten unserer derzeitigen Mitarbeiter war das, was sie taten, bevor sie Mitarbeiter wurden, nicht viel anders als das, was sie jetzt tun. + +Finde eine Leidenschaft und trage so bei, wie Du es für am besten hältst. Dann lass es seinen Lauf nehmen. Du musst kein Abzeichen haben, um hier respektiert zu werden. \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/install.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/install.md new file mode 100644 index 000000000..0de5ebd94 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/install.md @@ -0,0 +1,198 @@ +# Installation + +:::tip Schneller Test? + +Fühle Dich frei, Flarum in einem unserer [Demonstrationsforen](https://discuss.flarum.org/d/21101) auszuprobieren. Or set up your own forum in seconds at [Free Flarum](https://www.freeflarum.com), a free community service not affiliated with the Flarum team. + +::: + +## Server-Anforderungen + +Before you install Flarum, it's important to check that your server meets the requirements. Um Flarum ausführen zu können, brauchst du: + +* **Apache** (with mod\_rewrite enabled) or **Nginx** +* **PHP 7.3+** with the following extensions: curl, dom, fileinfo, gd, json, mbstring, openssl, pdo\_mysql, tokenizer, zip +* **MySQL 5.6+/8.0.23+** or **MariaDB 10.0.5+** +* **SSH (command-line) access** to run potentially necessary software maintenance commands, and Composer if you intend on using the command-line to install and manage Flarum extensions. + +## Installieren + +### Installing by unpacking an archive + +If you don't have SSH access to your server or you prefer not to use the command line, you can install Flarum by unpacking an archive. Below is a list of the available archives, make sure you choose the one that matches your PHP version and public path or lack thereof preference. + +| Flarum Version | PHP Version | Public Path | Type | Archive | +| -------------- | ----------------- | ----------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1.x | 8.3 (recommended) | No | ZIP | [flarum-v1.x-no-public-dir-php8.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.3.zip) | +| 1.x | 8.3 (recommended) | Yes | TAR.GZ | [flarum-v1.x-php8.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.3.tar.gz) | +| 1.x | 8.3 (recommended) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.3.tar.gz) | +| 1.x | 8.3 (recommended) | Yes | ZIP | [flarum-v1.x-php8.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.3.zip) | +| 1.x | 8.2 (recommended) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.2.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.2.tar.gz) | +| 1.x | 8.2 (recommended) | Yes | TAR.GZ | [flarum-v1.x-php8.2.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.2.tar.gz) | +| 1.x | 8.2 (recommended) | No | ZIP | [flarum-v1.x-no-public-dir-php8.2.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.2.zip) | +| 1.x | 8.2 (recommended) | Yes | ZIP | [flarum-v1.x-php8.2.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.2.zip) | +| 1.x | 8.1 | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.1.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.1.tar.gz) | +| 1.x | 8.1 | Yes | TAR.GZ | [flarum-v1.x-php8.1.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.1.tar.gz) | +| 1.x | 8.1 | No | ZIP | [flarum-v1.x-no-public-dir-php8.1.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.1.zip) | +| 1.x | 8.1 | Yes | ZIP | [flarum-v1.x-php8.1.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.1.zip) | +| 1.x | 8.0 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.0.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.0.tar.gz) | +| 1.x | 8.0 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php8.0.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.0.tar.gz) | +| 1.x | 8.0 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php8.0.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.0.zip) | +| 1.x | 8.0 (end of life) | Yes | ZIP | [flarum-v1.x-php8.0.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.0.zip) | +| 1.x | 7.4 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php7.4.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.4.tar.gz) | +| 1.x | 7.4 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php7.4.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.4.tar.gz) | +| 1.x | 7.4 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php7.4.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.4.zip) | +| 1.x | 7.4 (end of life) | Yes | ZIP | [flarum-v1.x-php7.4.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.4.zip) | +| 1.x | 7.3 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php7.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.3.tar.gz) | +| 1.x | 7.3 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php7.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.3.tar.gz) | +| 1.x | 7.3 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php7.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.3.zip) | +| 1.x | 7.3 (end of life) | Yes | ZIP | [flarum-v1.x-php7.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.3.zip) | + +### Installing using the Command Line Interface + +Flarum uses [Composer](https://getcomposer.org) to manage its dependencies and extensions. If you're not familiar with it, read [our guide](composer.md) for information on what it is and how to set it up. Afterwards, run this command in an empty location that you want Flarum to be installed in: + +```bash +composer create-project flarum/flarum . +``` + +While this command is running, you can configure your web server. You will need to make sure your webroot is set to `/path/to/your/forum/public`, and set up [URL Rewriting](#url-rewriting) as per the instructions below. + +When everything is ready, navigate to your forum in a web browser and follow the instructions to complete the installation. + +If you wish to install and update extensions from the admin dashboard, you need to also install the [Extension Manager](extensions.md) extension. + +```bash +composer require flarum/extension-manager:* +``` + +:::warning + +The extension manager allows an admin user to install any composer package. Only install the extension manager if you trust all of your forum admins with such permissions. + +::: + +## URL Rewriting + +### Apache + +Flarum includes a `.htaccess` file in the `public` directory – make sure it has been uploaded correctly. **Flarum will not function properly if `mod_rewrite` is not enabled or `.htaccess` is not allowed.** Be sure to check with your hosting provider (or your VPS) that these features are enabled. If you're managing your own server, you may need to add the following to your site configuration to enable `.htaccess` files: + +``` + + AllowOverride All + +``` + +This ensures that htaccess overrides are allowed so Flarum can rewrite URLs properly. + +Methods for enabling `mod_rewrite` vary depending on your OS. You can enable it by running `sudo a2enmod rewrite` on Ubuntu. `mod_rewrite` is enabled by default on CentOS. Don't forget to restart Apache after making modifications! + +### Nginx + +Flarum includes a `.nginx.conf` file – make sure it has been uploaded correctly. Then, assuming you have a PHP site set up within Nginx, add the following to your server's configuration block: + +```nginx +include /path/to/flarum/.nginx.conf; +``` + +### Caddy + +Caddy requires a very simple configuration in order for Flarum to work properly. Note that you should replace the URL with your own and the path with the path to your own `public` folder. If you are using a different version of PHP, you wil also need to change the `fastcgi` path to point to your correct PHP install socket or URL. + +``` +www.example.com { + root * /var/www/flarum/public + php_fastcgi unix//var/run/php/php7.4-fpm.sock + header /assets/* { + +Cache-Control "public, must-revalidate, proxy-revalidate" + +Cache-Control "max-age=25000" + Pragma "public" + } + file_server +} +``` +## Folder Ownership + +During installation, Flarum may request that you make certain directories writable. Modern operating systems are generally multi-user, meaning that the user you log in as is not the same as the user Flarum is running as. The user that Flarum is running as MUST have read + write access to: + +- The root install directory, so Flarum can edit `config.php`. +- The `storage` subdirectory, so Flarum can edit logs and store cached data. +- The `assets` subdirectory, so that logos and avatars can be uploaded to the filesystem. + +Extensions might require other directories, so you might want to recursively grant write access to the entire Flarum root install directory. + +There are several commands you'll need to run in order to set up file permissions. Please note that if your install doesn't show warnings after executing just some of these, you don't need to run the rest. + +First, you'll need to allow write access to the directory. On Linux: + +```bash +chmod 775 -R /path/to/directory +``` + +If that isn't enough, you may need to check that your files are owned by the correct group and user. By default, in most Linux distributions `www-data` is the group and user that both PHP and the web server operate under. You'll need to look into the specifics of your distro and web server setup to make sure. You can change the folder ownership in most Linux operating systems by running: + +```bash +chown -R www-data:www-data /path/to/directory +``` + +With `www-data` changed to something else if a different user/group is used for your web server. + +Additionally, you'll need to ensure that your CLI user (the one you're logged into the terminal as) has ownership, so that you can install extensions and manage the Flarum installation via CLI. To do this, add your current user (`whoami`) to the web server group (usually `www-data`) via `usermod -a -G www-data YOUR_USERNAME`. You will likely need to log out and back in for this change to take effect. + +Finally, if that doesn't work, you might need to configure [SELinux](https://www.redhat.com/en/topics/linux/what-is-selinux) to allow the web server to write to the directory. To do so, run: + +```bash +chcon -R -t httpd_sys_rw_content_t /path/to/directory +``` + +To find out more about these commands as well as file permissions and ownership on Linux, read [this tutorial](https://www.thegeekdiary.com/understanding-basic-file-permissions-and-ownership-in-linux/). If you are setting up Flarum on Windows, you may find the answers to [this Super User question](https://superuser.com/questions/106181/equivalent-of-chmod-to-change-file-permissions-in-windows) useful. + +:::caution Umgebungen können variieren + +Your environment may vary from the documentation provided, please consult your web server configuration or web hosting provider for the proper user and group that PHP and the web server operate under. + +::: + +:::danger Niemals die Berechtigung 777 verwenden + +You should never set any folder or file to permission level `777`, as this permission level allows anyone to access the content of the folder and file regardless of user or group. + +::: + +## Customizing Paths + +By default Flarum's directory structure includes a `public` directory which contains only publicly-accessible files. This is a security best-practice, ensuring that all sensitive source code files are completely inaccessible from the web root. + +However, if you wish to host Flarum in a subdirectory (like `yoursite.com/forum`), or if your host doesn't give you control over your webroot (you're stuck with something like `public_html` or `htdocs`), you can set up Flarum without the `public` directory. + +If you intend to install Flarum using one of the archives, you can simply use the `no-public-dir` (Public Path = No) [archives](#installing-by-unpacking-an-archive) and skip the rest of this section. If you're installing via Composer, you'll need to follow the instructions below. + +Simply move all the files inside the `public` directory (including `.htaccess`) into the directory you want to serve Flarum from. Then edit `.htaccess` and uncomment lines 9-15 in order to protect sensitive resources. For Nginx, uncomment lines 8-11 of `.nginx.conf`. + +You will also need to edit the `index.php` file and change the following line: + +```php +$site = require './site.php'; +``` + + Edit the `site.php` and update the paths in the following lines to reflect your new directory structure: + +```php +'base' => __DIR__, +'public' => __DIR__, +'storage' => __DIR__.'/storage', +``` + +Finally, check `config.php` and make sure the `url` value is correct. + +## Importing Data + +If you have an existing community and don't want to start from scratch, you may be able to import your existing data into Flarum. While there are no official importers yet, the community has made several unofficial importers: + +* [FluxBB](https://discuss.flarum.org/d/3867-fluxbb-to-flarum-migration-tool) +* [MyBB](https://discuss.flarum.org/d/5506-mybb-migrate-script) +* [phpBB](https://discuss.flarum.org/d/1117-phpbb-migrate-script-updated-for-beta-5) +* [SMF2](https://github.com/ItalianSpaceAstronauticsAssociation/smf2_to_flarum) + +These can be used for other forum software as well by migrating to phpBB first, then to Flarum. Be aware that we can't guarantee that these will work nor can we offer support for them. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/README.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/README.md new file mode 100644 index 000000000..d1b8efb11 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/README.md @@ -0,0 +1,7 @@ +--- +slug: '/internal' +--- + +# Interne Team Dokumentation + +Dies ist ein neuer Dokumentationsbereich, in dem wir einige Dokumente veröffentlichen werden, die intern vom Flarum-Team verwendet werden. Wir starten diesen Abschnitt, um unserer Community Transparenz darüber zu verschaffen, wie Flarum betrieben wird, und um denjenigen zu helfen, die zu Flarum beitragen möchten. \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md new file mode 100644 index 000000000..555e7977c --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md @@ -0,0 +1,28 @@ +# Bundled Extensions Policy + +This document is to assist in deciding what core features should be bundled or maintained by the Flarum project team. + +Understand that Flarum aims to have a lean and efficient team. To guarantee a transparent workload, we intentionally have a "this could be an extension" mentality. The acronym D.O.R.C. spells out our decision-making process. + +- **Density**: prevent bloating Flarum so that it becomes a burden to install on shared hosting plans with limited space. +- **Opinionatedness**: no extensions should be bundled that is only useful by only a limited amount of communities or on specific hosting environments. +- **Responsibility**: extensions that could easily be maintained by others should be maintained by others. +- **Complexity**: extensions that are complex in terms of design, frontend or backend code should not be a responsibility of the Flarum project team. + +### Density + +To prevent the installation size of Flarum from continuously increasing we need to protect it from extensions that bloat it. We should ship extensions with Flarum that, for instance, have kilobytes in media files. + +### Opinionatedness + +Our goal is to allow installation of Flarum, in its vanilla form, by any community on any hosting environment. This includes shared hosting environment as well. + +Releasing Flarum with extensions that add functionality specific to cloud based (AWS) installations or for corporate support communities, as such, is unwanted. + +### Responsibility + +Protecting the time of the project team is key. To do so we should empower the ecosystem in building extensions that it needs. Therefor we distance ourselves from the responsibility of building every and all extensions. The responsibility of extension development is held primarily by our community. + +### Complexity + +Complex extensions require a vast amount of time, not just for development, but also documentation and support. To protect the lean and efficient principles of the team, we will not take ownership of extensions that add this complexity. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md new file mode 100644 index 000000000..5b44436de --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md @@ -0,0 +1,87 @@ +# Extension Manager +This contains an explanation of how the extension manager works and what it has to offer. + +slightly outdated: see [the extensions guide for more](/extensions.md). + +## Inhalt +* Installieren, Aktualisieren und Entfernen von Erweiterungen. +* [Nach Updates suchen](#checking-for-updates). +* [Global Flarum-Update](#global-flarum-updates). +* [Patch-Minor Flarum-Updates](#patch-minor-flarum-updates). +* [Major Flarum-Update](#major-flarum-updates). +* [Flarum-Updates (global, minor, major)](#flarum-updates-global-minor-major). +* [Hintergrundaufgaben](#background-tasks). + +## Anforderungen +Es existieren einige Hindernisse, die behoben werden müssen, bevor dies verwendet werden kann. + +### Dateiberechtigungen +Der relevante Computer-Webbenutzer muss über Lese- und Schreibberechtigungen für Folgendes verfügen: `vendor`, `composer.json`, `composer.lock` und `storage`. Im Moment erscheint eine Warnung, wenn dies nicht der Fall ist, sollte dies vorzugsweise geändert werden, um nur die Dateien/Verzeichnisse zu erwähnen, in denen Berechtigungen fehlen, anstatt alle. + +![flarum lan_admin (3)](https://user-images.githubusercontent.com/20267363/135268536-f79d42ab-6e05-4e41-b2ab-d95ec7a8b021.png) + +### Pfad-Repository +In Entwicklungsumgebungen (und Produktion in seltenen Szenarien) sollte ein Pfad-Repository zu einem Verzeichnis existieren, das (meistens Entwicklungs-) Pakete enthält, der Pfad zu diesem Verzeichnis muss in einen absoluten Pfad geändert werden, da Composer sonst Probleme haben wird, einen Befehl auszuführen. Additionally the path repository by default has higher priority, so requiring an extension that exists in that repository will probably fail, unless a `*@dev` constraint is specified, in which case the extension manager should not be used for dev purposes anyway. + +There is currently now hint of any of this in the extension manager UI. + +## Gemeinsame Aktionen +Jede der oben aufgeführten Funktionen ist im Grunde ein oder zwei Composer-Befehle, und es existieren gemeinsame Aktionen/gemeinsames Verhalten zwischen ihnen allen. + +* Einschränkung des Zugriffs auf den Administrator. +* Validierung des bereitgestellten Paketnamens oder der Erweiterungs-ID, falls angegeben. +* Fehler beim Installieren einer vorhandenen Erweiterung, Aktualisieren oder Entfernen einer nicht vorhandenen Erweiterung usw +* Ausführen des Befehls. Dies [protokolliert die Ausgabe automatisch](#command-output-logging). +* [Fehler bei Befehlsfehler](#command-failure). +* Versenden eines Ereignisses. +* Wenn Du ein Update ausführst: + + Cache leeren. + + Migrationen ausführen. + + Assets veröffentlichen. + + Aktualisierungsprüfung durchführen und alle Erweiterungen protokolliere, die im Aktualisierungsprozess nicht auf ihre neuesten Versionen aktualisiert wurden. + +### Protokollierung der Befehlsausgabe +In Anbetracht dessen, dass dies noch experimentell ist und insbesondere aus Gründen der einfacheren Unterstützung, wird jede Befehlsausgabe genau wie die Flarum-Fehlerprotokolle in `storage/logs/composer` protokolliert, sodass Du zurückgehen und sehen kannst, was während einer Befehlsausführung geschehen ist. + +### Befehlsfehler +Wenn ein Composer-Befehl fehlschlägt (erkannt durch den Exit-Code), wird eine Ausnahme ausgelöst, die einen Grund enthält, der von der Ausnahme basierend auf dem Ausgabetext des Befehls erraten wird. Geschätzte Ursachen werden im Frontend in ordnungsgemäß erklärende Warnmeldungen umgewandelt. + +## Nach Updates suchen +Dies führt den Befehl `composer outdated -D --format json` aus, der nach Aktualisierungen von Paketen sucht, die direkt im Stammverzeichnis `composer.json` erforderlich sind, und die Ergebnisse im JSON-Format ausgibt. Nur Pakete, die von Composer als `semver-safe-update` und `update-possible` gekennzeichnet sind, werden angezeigt. + +Die Informationen zum letzten Update-Check werden in einer JSON-Einstellung gespeichert. + +![flarum lan_admin (4)](https://user-images.githubusercontent.com/20267363/135272032-9de37599-b364-4e42-b234-1113135eaa83.png) + +## Global Flarum Updates +Einfach den Befehl `command update --prefer-dist --no-dev -a --with-all-dependencies` ausführen, was nützlich ist, um alle Pakete zu aktualisieren. + +## Patch-Minor Flarum Updates +Dieser ändert direkt benötigte Paketversionen auf `*` und führt dann den Befehl `command update --prefer-dist --no-dev -a --with-all-dependencies` aus. + +![flarum lan_admin (5)](https://user-images.githubusercontent.com/20267363/135276114-ae438c2f-4122-45bd-b32f-690de3b56e25.png) + +## Major Flarum Updates +Dadurch werden die direkt erforderlichen Paketversionen auf `*` geändert, der Kern auf die neueste Hauptversionsanforderung geändert und dann derselbe Befehl oben ausgeführt. Bei einem Fehler kann richtig vermutet werden, dass einige Erweiterungen nicht mit der neuen Hauptversion kompatibel sind, die Ausnahmedetails enthalten eine Reihe von Erweiterungspaketnamen, die nicht kompatibel sind, es wird im Frontend gerendert, mit der Möglichkeit, ein `composer Why-not Flarum/Core 2.0` für weitere Details auszuführen. + +![große Update-Benutzeroberfläche](https://user-images.githubusercontent.com/20267363/143277865-8323fa9a-c80f-4015-baca-fce4d2b5d585.png) + +## Flarum Updates (global, minor, major) +Informationen über die zuletzt ausgeführten Updates werden in einer `last_update_run` JSON-Einstellung gespeichert, die ein Array von Erweiterungspaketnamen enthalten kann, die während des Prozesses nicht auf ihre neueste Version aktualisiert wurden. Dies wird im Frontend als Warnsymbolschaltflächen auf der Wenn Sie auf Erweiterungselemente klicken, wird ein `composer why-not` ausgeführt, das die Details des Fehlers in einem Modal anzeigt. + +![Benutzeroberfläche mit Liste von Erweiterungen, die Schaltflächen mit Warnsymbolen enthalten](https://user-images.githubusercontent.com/20267363/143278774-6fada0da-dead-474b-8dfa-feda5021134f.png) ![UI mit dem Modal, das die Details anzeigt](https://user-images.githubusercontent.com/20267363/143278786-d283db62-de96-4019-954e-932d0d6eac15.png) + +## Hintergrundaufgaben +Um Zeitüberschreitungsprobleme zu umgehen, können Composer-Befehle auch im Hintergrund ausgeführt werden, indem die Warteschlange verwendet wird. Benutzer können auf [Blomstras Datenbankwarteschlangenimplementierung](https://discuss.flarum.org/d/28151-database-queue-the-simplest-queue-even-for-shared-hosting) als grundlegende Warteschlangenlösung verwiesen werden. Es enthält Anweisungen zum Aktivieren der Warteschlange über einen Cron-Job. + +:::danger Cron-Job PHP-Prozessversion + +Es ist üblich, dass gemeinsam genutzte Hosts eine niedrige PHP-Version in SSH verwenden. Benutzer müssen darauf hingewiesen werden, dass sie sicherstellen müssen, dass der PHP-Prozess eine mit Flarum kompatible Version hat. Entweder durch manuelle Überprüfung oder durch Nachfragen bei ihren Gastgebern. + +::: + +![Extension Manager Queue Table Preview](/en/img/extension-manager-queue.png) + +## ZUTUN +- Mit Shared Hosting versuchen. +- Bessere Erklärung auf der Benutzeroberfläche zu Hintergrundaufgaben. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md new file mode 100644 index 000000000..067e2809f --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md @@ -0,0 +1,38 @@ +# PR Merging Policy + +Technical contributions to the Flarum source code go through a review process. Over the years we have tuned this process based on our experiences, our targeted development speed and availability. + +## What makes a great Pull Request? + +Great pull requests: + +- Have the [Pull Request template](https://github.com/flarum/.github/blob/main/PULL_REQUEST_TEMPLATE.md) filled out completely when opening a pull request. +- Do not combine different changes. Although tempting, don't change formatting of unrelated code. Stick to the one feature or change you wish to contribute. +- Have a related issue where the technical implementation has been agreed upon by the core team, or has been approved on by the core team through discussion on the official forums or other channels like Discord. +- Clearly explain the need for the change and list the areas where the pull request requires discussion. + +## Implementation Review Criteria + +- Adheres to our conventions or can be patched up easily after merging, follows proper code style. +- Are there any implementation details that could be done better through alternate technologies/technical approaches? +- Does not touch any lines outside of the intended changes, eg through formatting or compilation. +- If the changes are to code intended as a public API, has a proper doc block been included? + +## Merge Time! + +If all the checks in the template are met, **any** core developer may merge this PR. If the PR is authored by a core developer, they should probably be the ones to merge it. + +- Merging: + - GitHub offers several ways to merge a PR. Choose between the following strategies: + - **Merge** when the PR branch consists of atomic, well-described commits that are nice to have in the version history. + - **Squash** when lots of cleanup commits have accumulated. Please make sure to follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) spec for the squash commit. We usually find several commits from bots like StyleCI in these prefabricated commit messages, their commit messages should be removed. + +- After merging: + - Assign the related issue (if none exists, the pull request itself, but never both) to the appropriate milestone. + - Close all relevant issues (*if* they are closed completely). + - Regressions should be labeled as such and removed from the project board and milestone after merging. + - Check for follow-up tasks: + - Merge related PRs (language files, extensions, documentations). + - Documentation updates. + - Create issues for further follow-up tasks, if necessary. + diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/merging.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/merging.md new file mode 100644 index 000000000..0408b1bee --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/merging.md @@ -0,0 +1,29 @@ +# PR Merging Workflow + + +## Implementation Review Criteria + +- Adheres to our conventions or can be patched up easily after merging, follows proper code style. +- Are there any implementation details that could be done better through alternate technologies/technical approaches? +- Does not touch any lines outside of the intended changes, eg through formatting or compilation. +- If the changes are to code intended as a public API, has a proper doc block been included? + +## Merge Time! + +If all of the checks in the template are met, **any** core developer may merge this PR. If the PR is authored by a core developer, they should probably be the ones to merge it. + +- Merging: + - GitHub offers several ways to merge a PR. Choose between the following strategies: + - **Merge** when the PR branch consists of atomic, well-described commits that are nice to have in the version history. + - **Squash** when lots of cleanup commits have accumulated. Please make sure to follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) spec for the squash commit. + +- After merging: + - Make sure the *issue* (if none exists, the PR - but not both) belongs to the appropriate milestone and project board. + - PRs in extensions cannot be assigned to core milestones, so create a core issue that references it and add it to the milestone. + - Close all relevant issues (*if* they are closed completely). + - Regressions should be labeled as such and removed from the project board and milestone after merging. + - Check for follow-up tasks: + - Merge related PRs (language files, extensions, documentations). + - Documentation updates. + - Create issues for further follow-up tasks, if necessary. + diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md new file mode 100644 index 000000000..2c4300699 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md @@ -0,0 +1,89 @@ +# Paket-Manager +Darin wird erklärt, wie der Paketmanager funktioniert und was er zu bieten hat. + +## Inhalt +* Installieren, Aktualisieren und Entfernen von Erweiterungen. +* [Nach Updates suchen](#checking-for-updates). +* [Global Flarum-Update](#global-flarum-updates). +* [Patch-Minor Flarum-Updates](#patch-minor-flarum-updates). +* [Major Flarum-Update](#major-flarum-updates). +* [Flarum-Updates (global, minor, major)](#flarum-updates-global-minor-major). +* [Hintergrundaufgaben](#background-tasks). + +## Anforderungen +Es existieren einige Hindernisse, die behoben werden müssen, bevor dies verwendet werden kann. + +### Dateiberechtigungen +Der relevante Computer-Webbenutzer muss über Lese- und Schreibberechtigungen für Folgendes verfügen: `vendor`, `composer.json`, `composer.lock` und `storage`. Im Moment erscheint eine Warnung, wenn dies nicht der Fall ist, sollte dies vorzugsweise geändert werden, um nur die Dateien/Verzeichnisse zu erwähnen, in denen Berechtigungen fehlen, anstatt alle. + +![flarum lan_admin (3)](https://user-images.githubusercontent.com/20267363/135268536-f79d42ab-6e05-4e41-b2ab-d95ec7a8b021.png) + +### Pfad-Repository +In Entwicklungsumgebungen (und Produktion in seltenen Szenarien) sollte ein Pfad-Repository zu einem Verzeichnis existieren, das (meistens Entwicklungs-) Pakete enthält, der Pfad zu diesem Verzeichnis muss in einen absoluten Pfad geändert werden, da Composer sonst Probleme haben wird, einen Befehl auszuführen. Außerdem hat das Pfad-Repository standardmäßig eine höhere Priorität, sodass die Anforderung einer Erweiterung, die in diesem Repository vorhanden ist, wahrscheinlich fehlschlagen wird, es sei denn, es wird eine `*@dev`-Einschränkung angegeben, in diesem Fall sollte der Paketmanager ohnehin nicht für Entwicklungszwecke verwendet werden. + +Es existiert derzeit ein Hinweis darauf in der Paketmanager-Benutzeroberfläche. + +## Gemeinsame Aktionen +Jede der oben aufgeführten Funktionen ist im Grunde ein oder zwei Composer-Befehle, und es existieren gemeinsame Aktionen/gemeinsames Verhalten zwischen ihnen allen. + +* Einschränkung des Zugriffs auf den Administrator. +* Validierung des bereitgestellten Paketnamens oder der Erweiterungs-ID, falls angegeben. +* Fehler beim Installieren einer vorhandenen Erweiterung, Aktualisieren oder Entfernen einer nicht vorhandenen Erweiterung usw +* Ausführen des Befehls. Dies [protokolliert die Ausgabe automatisch](#command-output-logging). +* [Fehler bei Befehlsfehler](#command-failure). +* Versenden eines Ereignisses. +* Wenn Du ein Update ausführst: + + Cache leeren. + + Migrationen ausführen. + + Assets veröffentlichen. + + Aktualisierungsprüfung durchführen und alle Erweiterungen protokolliere, die im Aktualisierungsprozess nicht auf ihre neuesten Versionen aktualisiert wurden. + +### Protokollierung der Befehlsausgabe +In Anbetracht dessen, dass dies noch experimentell ist und insbesondere aus Gründen der einfacheren Unterstützung, wird jede Befehlsausgabe genau wie die Flarum-Fehlerprotokolle in `storage/logs/composer` protokolliert, sodass Du zurückgehen und sehen kannst, was während einer Befehlsausführung geschehen ist. + +### Befehlsfehler +Wenn ein Composer-Befehl fehlschlägt (erkannt durch den Exit-Code), wird eine Ausnahme ausgelöst, die einen Grund enthält, der von der Ausnahme basierend auf dem Ausgabetext des Befehls erraten wird. Geschätzte Ursachen werden im Frontend in ordnungsgemäß erklärende Warnmeldungen umgewandelt. + +## Nach Updates suchen +Dies führt den Befehl `composer outdated -D --format json` aus, der nach Aktualisierungen von Paketen sucht, die direkt im Stammverzeichnis `composer.json` erforderlich sind, und die Ergebnisse im JSON-Format ausgibt. Nur Pakete, die von Composer als `semver-safe-update` und `update-possible` gekennzeichnet sind, werden angezeigt. + +Die Informationen zum letzten Update-Check werden in einer JSON-Einstellung gespeichert. + +![flarum lan_admin (4)](https://user-images.githubusercontent.com/20267363/135272032-9de37599-b364-4e42-b234-1113135eaa83.png) + +## Global Flarum Updates +Einfach den Befehl `command update --prefer-dist --no-dev -a --with-all-dependencies` ausführen, was nützlich ist, um alle Pakete zu aktualisieren. + +## Patch-Minor Flarum Updates +Dieser ändert direkt benötigte Paketversionen auf `*` und führt dann den Befehl `command update --prefer-dist --no-dev -a --with-all-dependencies` aus. + +![flarum lan_admin (5)](https://user-images.githubusercontent.com/20267363/135276114-ae438c2f-4122-45bd-b32f-690de3b56e25.png) + +## Major Flarum Updates +Dadurch werden die direkt erforderlichen Paketversionen auf `*` geändert, der Kern auf die neueste Hauptversionsanforderung geändert und dann derselbe Befehl oben ausgeführt. Bei einem Fehler kann richtig vermutet werden, dass einige Erweiterungen nicht mit der neuen Hauptversion kompatibel sind, die Ausnahmedetails enthalten eine Reihe von Erweiterungspaketnamen, die nicht kompatibel sind, es wird im Frontend gerendert, mit der Möglichkeit, ein `composer Why-not Flarum/Core 2.0` für weitere Details auszuführen. + +![große Update-Benutzeroberfläche](https://user-images.githubusercontent.com/20267363/143277865-8323fa9a-c80f-4015-baca-fce4d2b5d585.png) + +## Flarum Updates (global, minor, major) +Informationen über die zuletzt ausgeführten Updates werden in einer `last_update_run` JSON-Einstellung gespeichert, die ein Array von Erweiterungspaketnamen enthalten kann, die während des Prozesses nicht auf ihre neueste Version aktualisiert wurden. Dies wird im Frontend als Warnsymbolschaltflächen auf der Wenn Sie auf Erweiterungselemente klicken, wird ein `composer why-not` ausgeführt, das die Details des Fehlers in einem Modal anzeigt. + +![Benutzeroberfläche mit Liste von Erweiterungen, die Schaltflächen mit Warnsymbolen enthalten](https://user-images.githubusercontent.com/20267363/143278774-6fada0da-dead-474b-8dfa-feda5021134f.png) ![UI mit dem Modal, das die Details anzeigt](https://user-images.githubusercontent.com/20267363/143278786-d283db62-de96-4019-954e-932d0d6eac15.png) + +## Hintergrundaufgaben +Um Zeitüberschreitungsprobleme zu umgehen, können Composer-Befehle auch im Hintergrund ausgeführt werden, indem die Warteschlange verwendet wird. Benutzer können auf [Blomstras Datenbankwarteschlangenimplementierung](https://discuss.flarum.org/d/28151-database-queue-the-simplest-queue-even-for-shared-hosting) als grundlegende Warteschlangenlösung verwiesen werden. Es enthält Anweisungen zum Aktivieren der Warteschlange über einen Cron-Job. + +:::danger Cron-Job PHP-Prozessversion + +Es ist üblich, dass gemeinsam genutzte Hosts eine niedrige PHP-Version in SSH verwenden. Benutzer müssen darauf hingewiesen werden, dass sie sicherstellen müssen, dass der PHP-Prozess eine mit Flarum kompatible Version hat. Entweder durch manuelle Überprüfung oder durch Nachfragen bei ihren Gastgebern. + +::: + +![Vorschau der Paket-Manager-Warteschlangentabelle](/en/img/package-manager-queue.png) + +## ZUTUN +- Mit Shared Hosting versuchen. +- Composer-Befehlsjob darf sich nicht überschneiden. +- Code TODOs. +- Bessere Erklärung auf der Benutzeroberfläche zu Hintergrundaufgaben. +- Szenario betrachten, in dem wir eine Erweiterung aktualisieren, die keine erforderliche Root-Abhängigkeit ist, z. B. Bundles. +- Jeweils eine Hintergrundaufgabe ausführen und verhindern, dass der Benutzer mehrere Aufgaben auslöst. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/languages.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/languages.md new file mode 100644 index 000000000..6985d142d --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/languages.md @@ -0,0 +1,29 @@ +# Sprachen + +Es ist ganz einfach, deiner Flarum-Basisinstallation eine neue Sprache hinzuzufügen. Befolgen einfach die nachstehenden Anweisungen, um das Sprachpaket deiner Wahl herunterzuladen und zu installieren. + +Nachdem du ein Sprachpaket hinzugefügt hast, kannst du es als [Standardsprache](#setting-the-default-language) für dein Forum festlegen. Und wenn du jemals feststellst, dass du eines deiner installierten Sprachpakete nicht benötigst, kannst du es jederzeit [deaktivieren](#disabling-a-language-pack). Wenn du Erweiterungen von Drittanbietern verwendest, stelle sicher, dass du [dies liest](#third-party-extensions), bevor du beginnst. + +## Installation des Sprachpakets + +Besuche zunächst das Tag [Extensions > Languages](https://discuss.flarum.org/t/languages) auf der Flarum Community-Site und suche ein Sprachpaket, das du installieren möchtest. + +Sprachpakete werden auf die gleiche Weise installiert wie [Erweiterungen](extensions.md). Die Sprache wird auf der Seite **Erweiterungen** der Admin-Oberfläche angezeigt und du kannst sie dort aktivieren. + +Das ist alles dazu! Du solltest jetzt in der Lage sein, die Sprachauswahl in der Kopfzeile deiner Website zu verwenden, um die Anzeige deines Forums auf die neue Sprache umzustellen. + +## Festlegen der Standardsprache + +Nachdem du ein Sprachpaket installiert und sichergestellt hast, dass es funktioniert, möchtest du es möglicherweise als Standardsprache für neue Benutzer und Gäste festlegen. Du kannst dies auf der Seite **Grundeinstellungen** der Admin-Oberfläche tun. + +## Deaktivieren eines Sprachpakets + +Wenn du entscheidest, dass du eine bestimmte Sprache nicht unterstützen musst, kannst du sie schließlich deaktivieren. Suche einfach das Sprachpaket auf der Seite **Erweiterungen** der Admin-Oberfläche und deaktiviere es. + +Das Deaktivieren einer Sprache kann nützlich sein, wenn du eine einsprachige Website betreiben und nicht möchtest, dass die Sprachauswahl im Website-Header angezeigt wird. Die Sprachauswahl ist ausgeblendet, wenn nur eine Sprache aktiviert ist. + +## Community-Erweiterungen + +Während Sprachpakete, die von der Flarum Community-Site heruntergeladen werden, im Allgemeinen Übersetzungen für alle Erweiterungen enthalten, die mit Flarum gebündelt sind, decken sie in der Regel _keine_ Community-Erweiterungen ab, die du möglicherweise installiert hast. Es ist Sache der Entwickler, Übersetzungen für ihre Erweiterungen bereitzustellen und zu pflegen. + +Bevor du also eine Community-Erweiterung installierst, sollten du überprüfen, ob sie Übersetzungen für jedes von dir installierte Sprachpaket enthält. Wenn du feststellst, dass eine Erweiterung eine von dir benötigte Sprache nicht unterstützt, wende dich bitte direkt an den Entwickler und veranlasse, dass die erforderlichen Übersetzungen hinzugefügt werden. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/mail.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/mail.md new file mode 100644 index 000000000..82308b601 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/mail.md @@ -0,0 +1,29 @@ +# E-Mail-Konfiguration + +Jede Community muss E-Mails senden, um die E-Mail-Verifizierung, das Zurücksetzen von Kennwörtern, Benachrichtigungen und andere Mitteilungen an Benutzer zu ermöglichen. Das Konfigurieren deines Forums zum Senden von E-Mails sollte einer deiner ersten Schritte als Administrator sein: Eine falsche Konfiguration führt zu Fehlern, wenn Benutzer versuchen, sich zu registrieren. + +## Verfügbare Treiber + +Flarum bietet standardmäßig mehrere Treiber, die unten aufgeführt und erklärt werden. Entwickler können auch [benutzerdefinierte E-Mail-Treiber über die Erweiterungen](extend/mail.md) hinzufügen. + +### SMTP + +Dies ist wahrscheinlich der am häufigsten verwendete E-Mail-Treiber, mit dem Du einen Host, Port/Verschlüsselung, Benutzername und Passwort für einen externen SMTP-Dienst konfigurieren kannst. Bitte beachte, dass das Verschlüsselungsfeld entweder `ssl` oder `tls` erwartet. + +### Mail + +Der `mail`-Treiber versucht, das sendmail/postfix-E-Mail-System zu verwenden, das in vielen Hosting-Servern enthalten ist. Du musst sendmail ordnungsgemäß auf deinem Server installieren und konfigurieren, damit dies funktioniert. + +### Mailgun + +Dieser Treiber verwendet dein [Mailgun](https://www.mailgun.com/)-Konto zum Senden von E-Mails. Du benötigst einen geheimen Schlüssel sowie die Domäne und Region aus deiner Mailgun-Konfiguration. + +Um den Mailgun-Treiber zu verwenden, musst Du das Guzzle-Composer-Paket (einen PHP-HTTP-Client) installieren. Du kannst dies tun, indem Du `composer require guzzlehttp/guzzle:^6.0|^7.0` im Stammverzeichnis deiner Flarum-Installation ausführst. + +### Log + +Der Log-Mail-Treiber sendet KEINE MAIL und wird hauptsächlich von Entwicklern verwendet. Es schreibt den Inhalt aller E-Mails in die Protokolldatei in `FLARUM_ROOT_DIRECTORY/storage/logs`. + +## E-Mail testen + +Sobald Du eine E-Mail-Konfiguration gespeichert hast, kannst Du auf der Seite „Mail“ des Admin-Dashboards auf die Schaltfläche „Test-Mail senden“ klicken, um sicherzustellen, dass deine Konfiguration funktioniert. Wenn Du einen Fehler siehst oder keine E-Mail erhälst, passe die Konfiguration an und versuche es erneut. Stelle sicher, dass Du deinen Spam überprüfst, wenn kein Fehler vorliegt, jedoch nichts in deinem Posteingang angezeigt wird. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/releases.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/releases.md new file mode 100644 index 000000000..6fb9a5869 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/releases.md @@ -0,0 +1,15 @@ +# Versionshinweise + + + + +Versionshinweise sind in der [Flarum Community](https://discuss.flarum.org/t/blog?sort=newest) zu finden. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/rest-api.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/rest-api.md new file mode 100644 index 000000000..7e91238d3 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/rest-api.md @@ -0,0 +1,375 @@ +# Consuming the REST API + +Flarum exposes a REST API which is used by the single page application but also available for external scripts. + +The API follows the best practices defined by the [JSON:API](https://jsonapi.org/) specification. + +:::info + +To extend the REST API with new endpoints, see [API and Data Flow](extend/api.md) in the developer documentation. + +::: + +## Authentication + +The single page app uses session cookies to authenticate against the API. External scripts can use stateless authentication using [API Keys](#api-keys) or [Access Tokens](#access-tokens). + +`GET` endpoints can be used without authentication. Only content visible to guests will be returned. Other endpoints generally cannot be used without authentication because of the [CSRF protection](#csrf-protection). + +### API keys + +API Keys are the primary way for scripts, tools and integrations to interact with Flarum. + +#### Creation + +There is currently no UI to manage API Keys, but they can be created manually in the `api_keys` table of the database. + +The following attributes can be filled: + +- `key`: Generate a long unique token (recommended: alpha-numerical, 40 characters) and set it here, this will be the token used in the `Authorization` header. +- `user_id`: Optional. If set, the key can only be used to act as the given user. + +The remaining attributes are either automatically filled or currently not used: + +- `id`: Will be filled by MySQL auto-increment. +- `allowed_ips`: Not implemented. +- `scopes`: Not implemented. +- `created_at`: Can be set to any date, but is meant for the date of creation of the key. +- `last_activity_at`: Will be updated automatically when the token is used. + +#### Usage + +Attach your key value to each API request using the `Authorization` header. Then provide the user ID you want to interact as at the end of the header: + + Authorization: Token YOUR_API_KEY_VALUE; userId=1 + +If a `user_id` value has been set for the key in the database, `userId=` will be ignored. Otherwise, it can be set to any valid user ID that exists in the database. + +### Access Tokens + +Access Tokens are short-lived tokens that belong to a specific user. + +Those tokens are used behind the scenes for cookie sessions. Their use in stateless API requests has the same effect as a regular session. The user last activity will be updated each time the token is used. + +#### Creation + +All users are allowed to create access tokens. To create a token, use the `/api/token` endpoint with the credentials of your user: + +``` +POST /api/token HTTP/1.1 + +{ + "identification": "Toby", + "password": "pass7word" +} + +HTTP/1.1 200 OK + +{ + "token": "YACub2KLfe8mfmHPcUKtt6t2SMJOGPXnZbqhc3nX", + "userId": "1" +} +``` + +At the moment, 3 token types exist, although only 2 types can be created via the REST API. + +- `session` tokens expire after 1h of inactivity. This is the default token type. +- `session_remember` tokens expire after 5 years of inactivity. They can be obtained by specifying `remember=1` in the request attributes. +- `developer` tokens never expire. They can only be created manually in the database at the moment. + +**All access tokens are deleted when the user logs out** (this includes `developer` tokens, although it is planned to change it). + +#### Usage + +Attach the returned `token` value to each API request using the `Authorization` header: + + Authorization: Token YACub2KLfe8mfmHPcUKtt6t2SMJOGPXnZbqhc3nX + +### CSRF Protection + +Most of the `POST`/`PUT`/`DELETE` API endpoints are protected against [Cross-site request forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery). This means stateless requests are not possible without authentication. + +When using an API Key or Access Token, CSRF protection is bypassed. + +## Endpoints + +This part of the documentation is still in progress. We are researching options to provide an automated documentation of the endpoints. + +Every extension adds new endpoints and attributes so it's difficult to provide a complete documentation of all endpoints. A good way to discover endpoints is to use the browser development tools to inspect requests made by the single page application. + +Below are a few examples of commonly used endpoints. JSON has been truncated to make reading easier. + +### List discussions + + GET /api/discussions + +```json +{ + "links": { + "first": "https://flarum.tld/api/discussions", + "next": "https://flarum.tld/api/discussions?page%5Boffset%5D=20" + }, + "data": [ + { + "type": "discussions", + "id": "234", + "attributes": { + "title": "Lorem Ipsum", + "slug": "234-lorem-ipsum", + "commentCount": 10, + "participantCount": 3, + "createdAt": "2022-01-01T10:20:30+00:00", + "lastPostedAt": "2022-01-05T10:20:30+00:00", + "lastPostNumber": 10, + "canReply": true, + "canRename": true, + "canDelete": true, + "canHide": true, + "isHidden": true, + "hiddenAt": "2022-01-06T10:20:30+00:00", + "lastReadAt": "2022-01-02T10:20:30+00:00", + "lastReadPostNumber": 2, + "isApproved": true, + "canTag": true, + "isLocked": false, + "canLock": true, + "isSticky": false, + "canSticky": true, + "canMerge": true, + "subscription": null + }, + "relationships": { + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + "lastPostedUser": { + "data": { + "type": "users", + "id": "64" + } + }, + "tags": { + "data": [ + { + "type": "tags", + "id": "3" + } + ] + }, + "firstPost": { + "data": { + "type": "posts", + "id": "668" + } + } + } + }, + { + "type": "discussions", + "id": "234", + "attributes": { + // [...] + }, + "relationships": { + // [...] + } + }, + // [...] more discussions + ], + "included": [ + { + "type": "users", + "id": "1", + "attributes": { + "username": "Admin", + "displayName": "Admin", + "avatarUrl": null, + "slug": "1" + } + }, + { + "type": "users", + "id": "64", + "attributes": { + "username": "Flarum", + "displayName": "Flarum", + "avatarUrl": "https://flarum.tld/assets/avatars/Z4hEncw0ndVqZ8be.png", + "slug": "64" + } + }, + { + "type": "tags", + "id": "3", + "attributes": { + "name": "Welcome", + "description": "Post interesting things here", + "slug": "welcome", + "color": "#888", + "backgroundUrl": null, + "backgroundMode": null, + "icon": "fas fa-bullhorn", + "discussionCount": 30, + "position": 1, + "defaultSort": null, + "isChild": false, + "isHidden": false, + "lastPostedAt": "2022-01-05T10:20:30+00:00", + "canStartDiscussion": true, + "canAddToDiscussion": true, + "isRestricted": false + } + }, + { + "type": "posts", + "id": "668", + "attributes": { + "number": 1, + "createdAt": "2022-01-01T10:20:30+00:00", + "contentType": "comment", + "contentHtml": "

Hello World

" + } + }, + // [...] more includes for the other discussions + ] +} +``` + +### Create discussion + + POST /api/discussions + +```json +{ + "data":{ + "type": "discussions", + "attributes": { + "title": "Lorem Ipsum", + "content": "Hello World" + }, + "relationships": { + "tags": { + "data": [ + { + "type": "tags", + "id": "1" + } + ] + } + } + } +} +``` + +The response includes the ID of the new discussion: + +```json +{ + "data": { + "type": "discussions", + "id": "42", + "attributes": { + "title": "Lorem Ipsum", + "slug": "42-lorem-ipsum", + "commentCount": 1 + // [...] other attributes + }, + "relationships": { + "posts": { + "data": [ + { + "type": "posts", + "id": "58" + } + ] + }, + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + // [...] other relationships + } + }, + "included":[ + { + "type": "posts", + "id": "38", + "attributes": { + "number": 1, + "contentType": "comment", + "contentHtml": "\u003Cp\u003EHello World\u003C\/p\u003E" + // [...] other attributes + } + } + // [...] other includes + ] +} +``` + +### Create user + + POST /api/users + +```json +{ + "data": { + "attributes": { + "username": "Flarum", + "email": "flarum@example.com", + "password": "correcthorsebatterystaple" + } + } +} +``` + +## Errors + +Flarum uses various HTTP status code and includes error descriptions that follow the [JSON:API error spec](https://jsonapi.org/format/#errors). + +Below are a few common errors you might encounter when using the REST API: + +### CSRF Token Mismatch + +If you receive a 400 HTTP error with `csrf_token_mismatch` message, it means the `Authorization` header is absent or invalid and Flarum attempted to authenticate through the session cookie. + +```json +{ + "errors": [ + { + "status": "400", + "code": "csrf_token_mismatch" + } + ] +} +``` + +### Validation errors + +Validation errors are returned with 422 HTTP status code. The name of the invalid field is returned as the `pointer` value. There can be multiple errors for a single field at the same time. + +```json +{ + "errors": [ + { + "status": "422", + "code": "validation_error", + "detail": "The username has already been taken.", + "source":{ + "pointer":"\/data\/attributes\/username" + } + }, + { + "status": "422", + "code": "validation_error", + "detail": "The email has already been taken.", + "source": { + "pointer":"\/data\/attributes\/email" + } + } + ] +} +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/scheduler.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/scheduler.md new file mode 100644 index 000000000..6123ce7c3 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/scheduler.md @@ -0,0 +1,55 @@ +# Scheduler + +The Flarum scheduler allows extensions to automate certain tasks effortlessly. In this guide we will see how to set it up. We won't go into the details of cron itself, but if you want to read more about it, I suggest you take a look at [this Wikipedia article](https://en.wikipedia.org/wiki/Cron) on cron. + +## Why should I care? + +Quite simply, a growing list of extensions now support handling certain functions automatically for you, completely behind the scenes. Wondering why `fof/drafts` 'scheduled drafts' are not posting, or `fof/best-answer` 'remind users to set a best answer after X days' does not fire? That'll be because they will setup themselves with the scheduler service, but without a one-liner cron job, nothing will happen! + +## What extensions currently use the scheduler? + +Some of the most popular examples are the following: + +- [FoF Best Answer](https://github.com/FriendsOfFlarum/best-answer) +- [FoF Drafts](https://github.com/FriendsOfFlarum/drafts) +- [FoF Sitemap](https://github.com/FriendsOfFlarum/sitemap) +- [FoF Open Collective](https://github.com/FriendsOfFlarum/open-collective) +- [FoF Github Sponsors](https://github.com/FriendsOfFlarum/github-sponsors) + +## Ok, let's get this setup! + +Most (if not all) Linux distros either come with, or can have, cron installed. For example, on Debian and Ubuntu based systems, you can install `cron` like this: + +``` +sudo apt-get update +sudo apt-get install cron +``` + +In case you are using a RHEL based Linux distribution (CentOS, AlmaLinux, Rocky Linux...), install cron like this: + +``` +sudo dnf update +sudo dnf install crontabs +``` + +Once you have cron installed, let's create the one and only entry you need for Flarum: + +``` +crontab -e +``` + +This will open the cron editor. You may or may not have other entries there. Add this line, and remember to leave an empty line at the bottom. + +``` +* * * * * cd /path-to-your-project && php flarum schedule:run >> /dev/null 2>&1 +``` + +`* * * * *` tells cron to run your command every minute. + +In case you want to use a different value and don't know exactly how cron expressions work, you can use a [cron expression generator](https://crontab.guru) to easily get the desired string. + +`cd /path-to-your-project && php flarum schedule:run` executes Flarum's scheduler to trigger any tasks currently waiting to be run. If PHP isn't in your system's path, you may need to experiment with setting the full path to PHP. + +Lastly `>> /dev/null 2>&1` suppresses any output from the command. + +Voila! Now any extension that registers a task to run, anything from every minute to daily, monthly, yearly - whatever - will now run on your server. diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/themes.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/themes.md new file mode 100644 index 000000000..7fb39f29e --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/themes.md @@ -0,0 +1,29 @@ +# Design + +Obwohl wir hart daran gearbeitet haben, Flarum so schön wie möglich zu machen, wird wahrscheinlich jede Community einige Optimierungen/Modifikationen vornehmen wollen, um sie ihrem gewünschten Stil anzupassen. + +## Admin-Dashboard + +The [admin dashboard](admin.md)'s Appearance page is a great first place to start customizing your forum. Hier kannst Du: + +- Designfarben auswählen +- Dunkelmodus und eine farbige Kopfzeile umschalten +- Ein Logo und Favicon hochladen (Symbol wird in Browser-Tabs angezeigt) +- HTML für benutzerdefinierte Kopf- und Fußzeilen hinzufügen +- [custom LESS/CSS](#css-theming) hinzufügen, um zu ändern, wie Elemente angezeigt werden + +## CSS-Design + +CSS ist eine Stylesheet-Sprache, die Browsern mitteilt, wie Elemente einer Webseite angezeigt werden sollen. Es ermöglicht uns, alles von Farben über Schriftarten bis hin zu Elementgröße und Positionierung bis hin zu Animationen zu ändern. Das Hinzufügen von benutzerdefiniertem CSS kann eine großartige Möglichkeit sein, deine Flarum-Installation an ein Thema anzupassen. + +Ein CSS-Tutorial würde den Rahmen dieser Dokumentation sprengen, aber es existieren viele großartige Online-Ressourcen, um die Grundlagen von CSS zu erlernen. + +:::tip + +Flarum verwendet tatsächlich LESS, was das Schreiben von CSS erleichtert, indem es Variablen, Bedingungen und Funktionen zulässt. + +::: + +## Erweiterungen + +Das flexible [Erweiterungssystem](extensions.md) von Flarum ermöglicht es dir, praktisch jeden Teil von Flarum hinzuzufügen, zu entfernen oder zu modifizieren. Wenn Du über das Ändern von Farben/Größen/Stilen hinaus erhebliche thematische Änderungen vornehmen möchtest, ist eine benutzerdefinierte Erweiterung definitiv der richtige Weg. Um zu erfahren, wie man eine Erweiterung erstellt, lese unsere [Extension-Dokumentation](extend/README.md)! diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md new file mode 100644 index 000000000..1358f7fc6 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md @@ -0,0 +1,56 @@ +# Problembehandlung + +If Flarum isn't installing or working as expected, the first thing you should do is *check again* whether your environment meets the [system requirements](install.md#server-requirements). If you're missing something that Flarum needs to run, you'll need to remedy that first. + +Next, you should take a few minutes to search the [Support forum](https://discuss.flarum.org/t/support) and the [issue tracker](https://github.com/flarum/core/issues). It's possible that someone has already reported the problem, and a fix is either available or on the way. If you've searched thoroughly and can't find any information about the problem, it's time to start troubleshooting. + +## Step 0: Activate debug mode + +:::danger Produktion überspringen + +Diese Debugging-Tools sind sehr nützlich, können jedoch Informationen offenlegen, die nicht öffentlich sein sollten. Diese sind in Ordnung, wenn du dich in einer Staging- oder Entwicklungsumgebung befindest, doch wenn du nicht weißt, was du tust, überspringe diesen Schritt in einer Produktionsumgebung. + +::: + +Bevor du fortfährst, solltest du die Debugging-Tools von Flarum aktivieren. Simply open up **config.php** with a text editor, change the `debug` value to `true`, and save the file. This will cause Flarum to display detailed error messages, giving you an insight into what's going wrong. + +If you've been seeing blank pages and the above change doesn't help, try setting `display_errors` to `On` in your **php.ini** configuration file. + +## Schritt 1: Allgemeine Korrekturen + +Viele Probleme können wie folgt behoben werden: + +* Lösche deinen Browser-Cache +* Lösche den Backend-Cache mit [`php flarum cache:clear`](console.md). +* Make sure your database is updated with [`php flarum migrate`](console.md). +* Ensure that the [email configuration](mail.md) in your admin dashboard is correct: invalid email config will cause errors when registering, resetting a password, changing emails, and sending notifications. +* Check that your `config.php` is correct. For instance, make sure that the right `url` is being used (`https` vs `http` and case sensitivity matter here!). +* One potential culprit could be a custom header, custom footer, or custom LESS. If your issue is in the frontend, try temporarily removing those via the Appearance page of the admin dashboard. + +You'll also want to take a look at the output of [`php flarum info`](console.md) to ensure that nothing major is out of place. + +## Step 2: Reproduce the issue + +Try to make the problem happen again. Pay careful attention to what you're doing when it occurs. Does it happen every time, or only now and then? Try changing a setting that you think might affect the problem, or the order in which you're doing things. Does it happen under some conditions, but not others? + +If you've recently added or updated an extension, you should disable it temporarily to see if that makes the problem go away. Make sure all of your extensions were meant to be used with the version of Flarum you're running. Outdated extensions can cause a variety of issues. + +Somewhere along the way you may get an idea about what's causing your issue, and figure out a way to fix it. But even if that doesn't happen, you will probably run across a few valuable clues that will help us figure out what's going on, once you've filed your bug report. + +## Step 3: Collect information + +If it looks like you're going to need help solving the problem, it's time to get serious about collecting data. Look for error messages or other information about the problem in the following places: + +* Displayed on the actual page +* Displayed in the browser console (Chrome: More tools -> Developer Tools -> Console) +* Recorded in the server's error log (e.g. `/var/log/nginx/error.log`) +* Recorded in PHP-FPM's error log (e.g. `/var/log/php7.x-fpm.log`) +* Recorded by Flarum (`storage/logs`) + +Copy any messages to a text file and jot down a few notes about *when* the error occurred, *what* you were doing at the time, and so on. Be sure to include any insights you may have gleaned about the conditions under which the issue does and doesn't occur. Add as much information as possible about your server environment: OS version, web server version, PHP version and handler, et cetera. + +## Step 4: Prepare a report + +Once you have gathered all the information you can about the problem, you're ready to file a bug report. Please follow the instructions on [Reporting Bugs](bugs.md). + +If you discover something new about the issue after filing your report, please add that information at the bottom of your original post. It's a good idea to file a report even if you have solved the problem on your own, since other users may also benefit from your solution. If you've found a temporary workaround for the problem, be sure to mention that as well. \ No newline at end of file diff --git a/i18n/de/docusaurus-plugin-content-docs/version-1.x/update.md b/i18n/de/docusaurus-plugin-content-docs/version-1.x/update.md new file mode 100644 index 000000000..21b090eb2 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/version-1.x/update.md @@ -0,0 +1,110 @@ +# Updating + +## From the Admin Dashboard + +:::info + +If you have the extension manager extension installed you can simply run the update from its interface and skip this page entirely. + +::: + +--- + +To update Flarum, you'll need to use [Composer](https://getcomposer.org). If you're not familiar with it (although you should be, because you need it to install Flarum), read [our guide](composer.md) for information on what it is and how to set it up. + +If updating across major versions (e.g. <=0.1.0 to 1.x.x, 1.x.x to 2.x.x, ...), make sure to read the appropriate "major version update guide" before running the general upgrade steps. + +## General Steps + +**Step 1:** Make sure all your extensions have versions compatible with the Flarum version you're trying to install. This is only needed across major versions (e.g. you probably don't need to check this if upgrading from v1.0.0 to v1.1.0, assuming your extensions follow recommended versioning). You can check this by looking at the extension's [Discuss thread](https://discuss.flarum.org/t/extensions), searching for it on [Packagist](http://packagist.org/), or checking databases like [Extiverse](https://extiverse.com). You'll need to remove (not just disable) any incompatible extensions before updating. Please be patient with extension developers! + +**Step 2:** Take a look at your `composer.json` file. Unless you have a reason to require specific versions of extensions or libraries, you should set the version string of everything except `flarum/core` to `*` (including `flarum/tags`, `flarum/mentions`, and other bundled extensions). Make sure `flarum/core` is NOT set to `*`. If you're targeting a specific version of Flarum, set `flarum/core` to that (e.g. `"flarum/core": "v0.1.0-beta.16`). If you just want the most recent version, use `"flarum/core": "^1.0"`. + +**Step 3:** If your local install uses [local extenders](extenders.md), make sure they are up to date with changes in Flarum. + +**Step 4:** We recommend disabling third-party extensions in the admin dashboard before updating. This isn't strictly required, but will make debugging easier if you run into issues. + +**Step 5:** Make sure your PHP version is supported by the version of Flarum you are trying to upgrade to, and that you are using Composer 2 (`composer --version)`. + +**Step 6:** Finally, to update, run: + +``` +composer update --prefer-dist --no-plugins --no-dev -a --with-all-dependencies +php flarum migrate +php flarum cache:clear +``` + +**Step 7:** If applicable, restart your PHP process and opcache. + +## Major Version Update Guides + +### Updating from Beta (<=0.1.0) to Stable v1 (^1.0.0) + +1. Do steps 1-5 above. +2. Change the version strings of all bundled extensions (`flarum/tags`, `flarum/mentions`, `flarum/likes`, etc) in `composer.json` from `^0.1.0` to `*`. +3. Change `flarum/core`'s version string in `composer.json` from `^0.1.0` to `^1.0`. +4. Remove the `"minimum-stability": "beta",` line from your `composer.json` +5. Do steps 6 and 7 above. + +## Troubleshooting Issues + +There are 2 main places where you might run into errors when updating Flarum: while running the update command itself, or when accessing the forum after updating. + +### Errors While Updating + +Here we'll go through several common types of issues while trying to update Flarum. + +--- + +If the output is short and contains: + +``` +Nothing to modify in lock file +``` + +Or does not list `flarum/core` as an updated package, and you are not on the latest flarum version: + +- Revisit step 2 above, make sure that all third party extensions have an asterisk for their version string. +- Make sure your `flarum/core` version requirement isn't locked to a specific minor version (e.g. `v0.1.0-beta.16` is locked, `^1.0.0` isn't). If you're trying to update across major versions of Flarum, follow the related major version update guide above. + +--- + +For other errors, try running `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO` + +If the output looks something like this: + +``` +flarum/flarum - requires flarum/core (v0.1.0-beta.15) +fof/moderator-notes 0.4.4 requires flarum/core (>=0.1.0-beta.15 <0.1.0-beta.16) +jordanjay29/flarum-ext-summaries 0.3.2 requires flarum/core (>=0.1.0-beta.14 <0.1.0-beta.16) +flarum/core v0.1.0-beta.16 requires dflydev/fig-cookies (^3.0.0) +flarum/flarum - does not require dflydev/fig-cookies (but v2.0.3 is installed) +flarum/core v0.1.0-beta.16 requires franzl/whoops-middleware (^2.0.0) +flarum/flarum - does not require franzl/whoops-middleware (but 0.4.1 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/bus (^8.0) +flarum/flarum - does not require illuminate/bus (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/cache (^8.0) +flarum/flarum - does not require illuminate/cache (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/config (^8.0) +flarum/flarum - does not require illuminate/config (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/container (^8.0) +flarum/flarum - does not require illuminate/container (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/contracts (^8.0) +flarum/flarum - does not require illuminate/contracts (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/database (^8.0) +flarum/flarum - does not require illuminate/database (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/events (^8.0) +flarum/flarum - does not require illuminate/events (but v6.20.19 is installed) +... (this'll go on for a bit) +``` + +It is very likely that some of your extensions have not yet been updated. + +- Revisit step 1 again, make sure all your extensions have versions compatible with the core version you want to upgrade to. Remove any that don't. +- Make sure you're running `composer update` with all the flags specified in the update step. + +If none of this fixes your issue, feel free to reach out on our [Support forum](https://discuss.flarum.org/t/support). Make sure to include the output of `php flarum info` and `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO`. + +### Errors After Updating + +If you are unable to access your forum after updating, follow our [troubleshooting instructions](troubleshoot.md). diff --git a/i18n/en/docusaurus-plugin-content-docs/current.json b/i18n/en/docusaurus-plugin-content-docs/current.json index b62ad0f66..466762ccc 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current.json +++ b/i18n/en/docusaurus-plugin-content-docs/current.json @@ -1,6 +1,6 @@ { "version.label": { - "message": "Next", + "message": "2.x", "description": "The label for version current" }, "sidebar.guideSidebar.category.Introduction": { @@ -39,4 +39,4 @@ "message": "Internal Docs", "description": "The label for category Internal Docs in sidebar internalSidebar" } -} \ No newline at end of file +} diff --git a/i18n/es/docusaurus-plugin-content-docs/current.json b/i18n/es/docusaurus-plugin-content-docs/current.json index b62ad0f66..466762ccc 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current.json +++ b/i18n/es/docusaurus-plugin-content-docs/current.json @@ -1,6 +1,6 @@ { "version.label": { - "message": "Next", + "message": "2.x", "description": "The label for version current" }, "sidebar.guideSidebar.category.Introduction": { @@ -39,4 +39,4 @@ "message": "Internal Docs", "description": "The label for category Internal Docs in sidebar internalSidebar" } -} \ No newline at end of file +} diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/README.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/README.md new file mode 100644 index 000000000..b3b09e6bd --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/README.md @@ -0,0 +1,45 @@ +- - - +slug: / +- - - + +# Acerca de Flarum + +Flarum es una plataforma de discusión increíblemente sencilla para su sitio web. Es rápido y fácil de usar, con todas las características que necesitas para dirigir una comunidad exitosa. It's also extremely extensible, allowing for ultimate customizability. + +![Flarum Home Screenshot](/en/img/home_screenshot.png) + +## Objetivos + +Flarum es el sucesor combinado de [esoTalk](https://github.com/esotalk/esoTalk) y [FluxBB](https://fluxbb.org). Está diseñado para ser: + +* **Rápido y simple.** Sin desorden, sin relleno, sin dependencias complejas. Flarum está construido con PHP por lo que es rápido y fácil de desplegar. La interfaz está impulsada por [Mithril](https://mithril.js.org), un marco de trabajo de JavaScript de alto rendimiento con una pequeña huella. + +* **Bonito y responsivo.** Este es el software de foros hecho para personas. Flarum está cuidadosamente diseñado para ser consistente e intuitivo en todas las plataformas, desde el principio. + +* **Potente y extensible.** Personalice, extienda e integre Flarum para adaptarlo a su comunidad. La arquitectura de Flarum es increíblemente flexible, con una [potente API de extensión](/extend/). + +* **Gratis y libre.** Flarum está liberado bajo la [licencia MIT](https://github.com/flarum/flarum/blob/master/LICENSE). + +You can read more about our [philosophy and values for Flarum here](https://discuss.flarum.org/d/28869-flarum-philosophy-and-values). + +## Help the Flarum Project + +Flarum is [free, open source](https://github.com/flarum/core) software, maintained and governed by volunteers. We rely on community contributions to help us improve and expand Flarum. + +🧑‍💻 If you're a developer, consider [contributing to Flarum's core or bundled extensions](contributing.md). This is **the** most efficient way to help Flarum, and your work can have a lot of impact: there are thousands of Flarum sites out there, with millions of total end users. + +🧩 If there's a feature you're missing, or a theme idea you have, [writing a custom extension](extend/README.md) will make Flarum that much better for you and others. + +Esta guía de usuario te ayudará a crear tu propio foro usando Flarum y te enseñará los fundamentos básicos de la gestión de tu comunidad. + +🌐 If you speak multiple languages, you could [contribute translations](extend/language-packs.md) to could help make Flarum accessible to countless users around the world. + +💸 The Flarum Foundation doesn't make money off of Flarum, but does have bills to pay. Donations via [GitHub Sponsors](https://github.com/sponsors/flarum) or [OpenCollective](https://opencollective.com/flarum) are always gratefully received. In the past, we've also been able to support some of our core developers financially, so they could work on Flarum part time. This wouldn't be possible without your financial support. + +🧑‍🤝‍🧑 Join [our community](https://discuss.flarum.org) to talk about Flarum development, get help with your instance, or just meet cool people! If you're experienced with Flarum, you can also help out beginners! + +🐛 If there's a bug that's bothering you, or a feature idea on your mind, we can't know about it unless you tell us! We track bugs, suggestions, and future development plans [via GitHub issues](https://github.com/flarum/core/issues). If there's already an issue open, adding likes and (constructive) additional information can be very helpful! + +📣 And if you like Flarum, please consider blogging/tweeting/talking about it! More people aware of Flarum leads to more people engaging with Flarum, and therefore more activity, better extensions, and faster development. + +Flarum wouldn't be possible without our phenomenal community. If you're interested in contributing, see our [developer contribution](contributing.md) and [other contribution](contributing-docs-translations.md) docs for more information. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/admin.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/admin.md new file mode 100644 index 000000000..e2f0bc93c --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/admin.md @@ -0,0 +1,13 @@ +# Panel de Administración + +El Panel de Administración de Flarum es una interfaz fácil de usar para administrar su foro. Solo está disponible para los usuarios del [grupo] "Admin" (permissions.md). Para acceder al panel de administración, haz clic en tu **Nombre** en la parte superior derecha de la pantalla, y selecciona **Administración**. + +The Admin Dashboard has the following sections, being: +- **Dashboard** - Shows the main Admin Dashboard, containing statistics and other relevant information. +- **Basics** - Shows the options to set basic forum details such as Name, Description, and Welcome Banner. +- **Email** - Allows you to configure your E-Mail settings. Refer [here](https://docs.flarum.org/mail) for more information. +- **Permissions** - Shows the permissions for each user group, and allows you to configure global and specific scopes. +- **Appearance** - Allows you to customize the forum's colors, branding and add additional CSS for customization. +- **Users** - Provides you with a paginated list of all the users in the forum, and grants you the ability to edit the user or take administrative actions. + +Apart from the above mentioned sections, the Admin Dashboard also allows you to manage your Extensions (including the flarum core extensions such as Tags) under the _Features_ section. Extensions which modify the forum theme, or allow you to use multiple languages are categorized under the _Themes_ and _Languages_ section respectively. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/bugs.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/bugs.md new file mode 100644 index 000000000..85e8ea193 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/bugs.md @@ -0,0 +1,28 @@ +# Reporting Bugs + +:::danger Security Vulnerabilities + +If you discover a security vulnerability within Flarum, please follow our [security policy](https://github.com/flarum/core/security/policy) so we can address it promptly. + +::: + +Thank you for helping us test Flarum. We're happy to have you on the team! We need people who can *troubleshoot issues patiently* and *communicate them clearly*. As you probably know, good bug reporting takes some time and effort. If you're fine with that, then let's get started! + +## Duplicates + +Found a bug already? Wonderful! We'd love to hear about it — but first you should check around to make sure you're not wasting your time on a known issue: + +- Search our [Support forum](https://discuss.flarum.org/t/support) to see if it's already been reported. +- We could be working on a fix, so search our [issue tracker](https://github.com/flarum/core/issues) too. + +If you've searched *thoroughly* and come up empty-handed, we'll welcome your report. If it's just a simple issue (a misspelled word or graphics glitch, for example) skip to the next paragraph. But if you're seeing errors, or something is clearly broken, we'll need you to gather some information first. Please head over to our [Troubleshooting](troubleshoot.md) guide and follow the instructions there. Collect as much info as you can! + +## Reporting + +We track issues on GitHub. Make sure you open your issue in the [correct repository](https://github.com/flarum), and fill out all of the information in the Bug Report template. + +If you can, check if the issue is reproducible with the latest version of Flarum. If you are using a pre-release or development version, please indicate the specific version you are using. + +Remember: the goal of a bug report is to make it easy for us to replicate the bug and fix it. You might want to read [this article](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html) for some useful tips on how to write an effective bug report. It is **required** that you clearly describe the steps necessary to reproduce the issue you are running into. Issues with no clear reproduction steps will not be triaged. If an issue labeled "needs verification" receives no further input from the issue author for more than 5 days, it will be closed. + +Once you've posted your report, we'd ask that you please *follow the discussion* and wait patiently. We may need to ask for further details or clarification; but we've always got plenty to do, and it could be a while before we can give your report the time it deserves. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md new file mode 100644 index 000000000..72e6c104a --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md @@ -0,0 +1,51 @@ +# Código de conducta + +### _¡Bienvenido a la Comunidad de Flarum!_ + +... And thanks for joining us! We're excited about Flarum, and are always happy to meet people who feel the same way. Queremos que *todos* aprovechen al máximo Flarum y la comunidad de Flarum, por lo que te pedimos que leas y sigas estas directrices. Estas se aplican ya sea que estés usando nuestro foro, el chat de Discord, comunicándote en GitHub, o cualquier otra forma de comunicación sin la comunidad de Flarum. + +### Por encima de todo, ¡mantén la calma! + +Todos estamos aquí para hablar de Flarum, y para trabajar juntos para hacer una aplicación aún mejor. Criticar ideas (mediante argumentos razonados, por supuesto) es una parte importante de eso. Pero no nos dejemos llevar por los ataques personales, porque la negatividad sólo estorba. Te pedimos que evites lo siguiente: + +- Lenguaje ofensivo o abusivo, así como cualquier tipo de discurso de odio +- Mensajes que pretendan acosar, suplantar o difamar a otros +- Eliminación innecesaria de contenidos publicados +- Intentos de abusar o exponer la información privada de otros +- Contenido obsceno o sexualmente explícito +- Spam, suplantación de identidad y cualquier otra acción que pretenda desprestigiar este sitio +- Discusión de la piratería de software y temas similares + +*Todo lo anterior es motivo de acción por parte de los moderadores.* Si tienes un problema con otro miembro, te pedimos que no te enfrentes a él. Si es en el foro, utiliza el comando *Informar* en el mensaje en cuestión, y luego deja que el personal se encargue de la situación. Otherwise, report the violation using our [contact page](https://flarum.org/foundation/contact), option Legal. + +Nuestros moderadores pueden editar o borrar cualquier contenido que sea ofensivo o que interrumpa el flujo de comunicación. Las infracciones graves o repetidas pueden llevar a la suspensión de la cuenta del usuario infractor. Así que, ya sabes, *sé guay*. 😎 + +### Hazte Oír + +¿Quieres iniciar una nueva discusión? Primero, asegúrate de leer [nuestro FAQ](faq.md) y sigue los enlaces para asegurarte de que estás completamente informado sobre el proyecto. A continuación, dedícate a navegar por el foro, familiarízate con [el sistema de etiquetas](https://discuss.flarum.org/tags) y haz algunas búsquedas de palabras clave relacionadas con tu tema: *¡podría ser que alguien ya haya iniciado una discusión al respecto!* + +Cuando estés seguro de que estás preparado para iniciar una discusión, ten en cuenta los siguientes puntos: + +- ¡Dale un buen título! Obtendrás mejores resultados si tu título deja claro de qué quieres hablar. +- Elige la(s) etiqueta(s) adecuada(s). Esto aumentará la probabilidad de que tu mensaje sea leído y respondido rápidamente. +- *No* publiques repetidamente sobre el mismo tema, ya que esto tiende a tener el efecto contrario. +- If not using a tag set aside for multilingual use, *post in English only.* We can't help you if we don't understand your posts. +- Recuerda que no es necesario que firmes tus mensajes. Tenemos tu perfil para saber quién eres. + +Por favor, haz el esfuerzo de ayudarnos a mantener las cosas organizadas. El tiempo que pasamos ordenando es tiempo que no podemos dedicar a conocerte, a discutir tus asuntos y a hablar de Flarum. Y eso, al fin y al cabo, es lo que hemos venido a hacer. + +### Haz que tu respuesta cuente + +Te tomas el tiempo de participar en una discusión, con la esperanza de que los demás lean tus ideas y las tengan en cuenta. Así que, ¿por qué no hacer un esfuerzo para que tu respuesta merezca la pena? + +- No respondas a un título. Tómate un tiempo para *leer* el texto y, al menos, *escanear* el resto de la conversación. +- Pregúntate si tu respuesta aporta algo a la discusión. Si no lo hace, piénsalo mejor antes de publicar. +- Evita hacer posts de una sola palabra sólo para estar de acuerdo con alguien; para eso puedes usar el botón "Me gusta". +- Evita hacer varios mensajes seguidos cuando uno sería suficiente. Esto es un foro, no una sala de chat. +- Si tu respuesta puede desviar el curso de la discusión, considera la posibilidad de iniciar una nueva discusión. +- Si sólo quieres publicar una tontería como prueba, hazlo en la etiqueta [Test Posting](https://discuss.flarum.org/t/sandbox). +- Asegúrate de que tus respuestas aportan comentarios constructivos y apoyo para permitir una comunidad inclusiva. + +Nadie se va a quejar por una broma o un comentario inteligente ocasional. Nos gusta que el ambiente sea distendido. Pero para que las cosas sigan siendo productivas, te pedimos que trates de evitar el descarrilamiento de la discusión. + +> Gracias a Dominion por su ayuda en la elaboración de estas directrices. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/composer.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/composer.md new file mode 100644 index 000000000..c2d38a451 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/composer.md @@ -0,0 +1,152 @@ + +# Composer + +Flarum uses a program called [Composer](https://getcomposer.org) to manage its dependencies and extensions. You'll need to use composer if you want to: + +- Install or update Flarum through the command line +- Install, update, or remove Flarum extensions through the command line + +This guide is provided as a brief explanation of Composer. We highly recommend consulting the [official documentation](https://getcomposer.org/doc/00-intro.md) for more information. + +:::tip ¿Prueba rápida? + +On shared hosting it is recommended to use the Extension Manager extension instead of Composer. It is a graphical interface for Composer that allows you to install, update and remove extensions without the need for SSH access. You can directly install Flarum using an archive file, without the need for Composer. With the extension manager pre-installed, check the [installation guide](install.md#installing-by-unpacking-an-archive) for more information. + +::: + +## What is Composer? + +> Composer is a tool for dependency management in PHP. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you. — [Composer Introduction](https://getcomposer.org/doc/00-intro.md](https://getcomposer.org/doc/00-intro.md)) + +Each Flarum installation consists primarily of Flarum core and a set of [extensions](extensions.md). Each of these has its own dependencies and releases. + +Back in the day, forum frameworks would manage extensions by having users upload zip files with the extension code. That seems simple enough, but issues quickly become evident: + +- Uploading random zip files from the internet tends to be a bad idea. Requiring that extensions be downloaded from a central source like [Packagist](https://packagist.org/) makes it somewhat more tedious to spam malicious code, and ensures that source code is available on GitHub for free/public extensions. +- Let's say Extension A requires v4 of some library, and Extension B requires v5 of that same library. With a zip-based solution, either one of the two dependencies could override the other, causing all sorts of inconsistent problems. Or both would attempt to run at once, which would cause PHP to crash (you can't declare the same class twice). +- Zip files can cause a lot of headache if trying to automate deployments, run automated tests, or scale to multiple server nodes. +- There is no good way to ensure conflicting extension versions can't be installed, or that system PHP version and extension requirements are met. +- Sure, we can upgrade extensions by replacing the zip file. But what about upgrading Flarum core? And how can we ensure that extensions can declare which versions of core they're compatible with? + +Composer takes care of all these issues, and more! + +## Flarum and Composer + +When you go to [install Flarum](install.md#installing), you're actually doing 2 things: + +1. Downloading a boilerplate "skeleton" for Flarum. This includes an `index.php` file that handles web requests, a `flarum` file that provides a CLI, and a bunch of web server config and folder setup. This is taken from the [`flarum/flarum` github repository](https://github.com/flarum/flarum), and doesn't actually contain any of the code necessary for Flarum to run. +2. Installing `composer` packages necessary for Flarum, namely Flarum core, and several bundled extensions. These are called by the `index.php` and `flarum` files from step 1, and are the implementation of Flarum. These are specified in a `composer.json` file included in the skeleton. + +When you want to update Flarum or add/update/remove extensions, you'll do so by running `composer` commands. Each command is different, but all commands follow the same general process: + +1. Update the `composer.json` file to add/remove/update the package. +2. Do a bunch of math to get the latest compatible versions of everything if possible, or figure out why the requested arrangement is impossible. +3. If everything works, download new versions of everything that needs to be updated. If not, revert the `composer.json` changes + +When running `composer.json` commands, make sure to pay attention to the output. If there's an error, it'll probably tell you if it's because of extension incompatibilities, an unsupported PHP version, missing PHP extensions, or something else. + +### The `composer.json` File + +As mentioned above, the entire composer configuration for your Flarum site is contained inside the `composer.json` file. You can consult the [composer documentation](https://getcomposer.org/doc/04-schema.md) for a specific schema, but for now, let's go over an annotated `composer.json` from `flarum/flarum`: + +```json +{ + // This following section is mostly just metadata about the package. + // For forum admins, this doesn't really matter. + "name": "flarum/flarum", + "description": "Delightfully simple forum software.", + "type": "project", + "keywords": [ + "forum", + "discussion" + ], + "homepage": "https://flarum.org/", + "license": "MIT", + "authors": [ + { + "name": "Flarum", + "email": "info@flarum.org", + "homepage": "https://flarum.org/team" + } + ], + "support": { + "issues": "https://github.com/flarum/core/issues", + "source": "https://github.com/flarum/flarum", + "docs": "https://flarum.org/docs/" + }, + // End of metadata + + // This next section is the one we care about the most. + // It's a list of packages we want, and the versions for each. + // We'll discuss this shortly. + "require": { + "flarum/core": "^1.0", + "flarum/approval": "*", + "flarum/bbcode": "*", + "flarum/emoji": "*", + "flarum/lang-english": "*", + "flarum/flags": "*", + "flarum/likes": "*", + "flarum/lock": "*", + "flarum/markdown": "*", + "flarum/mentions": "*", + "flarum/nicknames": "*", + "flarum/pusher": "*", + "flarum/statistics": "*", + "flarum/sticky": "*", + "flarum/subscriptions": "*", + "flarum/suspend": "*", + "flarum/tags": "*" + }, + + // Various composer config. The ones here are sensible defaults. + // See https://getcomposer.org/doc/06-config.md for a list of options. + "config": { + "preferred-install": "dist", + "sort-packages": true + }, + + // If composer can find a stable (not dev, alpha, or beta) version + // of a package, it should use that. Generally speaking, production + // sites shouldn't run beta software unless you know what you're doing. + "prefer-stable": true +} +``` + +Let's focus on that `require` section. Each entry is the name of a composer package, and a version string. To read more about version strings, see the relevant [composer documentation](https://semver.org/). + +For Flarum projects, there's several types of entries you'll see in the `require` section of your root install's `flarum/core`: + +- You MUST have a `flarum/core` entry. This should have an explicit version string corresponding to the major release you want to install. For Flarum 1.x versions, this would be `^1.0`. +- You should have an entry for each extension you've installed. Some bundled extensions are included by default (e.g. `flarum/tags`, `flarum/suspend`, etc), [others you'll add via composer commands](extensions.md). Unless you have a reason to do otherwise (e.g. you're testing a beta version of a package), we recommend using an asterisk as the version string for extensions (`*`). This means "install the latest version compatible with my flarum/core". +- Some extensions / features might require PHP packages that aren't Flarum extensions. For example, you need the guzzle library to use the [Mailgun mail driver](mail.md). In these cases, the instructions for the extension/feature in question should explain which version string to use. + +## How to install Composer? + +As with any other software, Composer must first be [installed](https://getcomposer.org/download/) on the server where Flarum is running. There are several options depending on the type of web hosting you have. + +### Dedicated Web Server + +In this case you can install composer as recommended in the Composer [guide](https://getcomposer.org/doc/00-intro.md#system-requirements) + +### Managed / Shared hosting + +If Composer is not preinstalled (you can check this by running `composer --version`), you can use a [manual installation](https://getcomposer.org/composer-stable.phar). Just upload the composer.phar to your folder and run `/path/to/your/php7 composer.phar COMMAND` for any command documented as `composer COMMAND`. + +:::danger + +Some articles on the internet will mention that you can use tools like a PHP shell. If you are not sure what you are doing or what they are talking about - be careful! An unprotected web shell is **extremely** dangerous. + +::: + +## How do I use Composer? + +You'll need to use Composer over the **C**ommand-**l**ine **i**nterface (CLI). Be sure you can access your server over **S**ecure **Sh**ell (SSH). + +Once you have Composer installed, you should be able to run Composer commands in your SSH terminal via `composer COMMAND`. + +:::info Optimizations + +After most commands, you'll want to run `composer dump-autoload -a`. Essentially, this caches PHP files so they run faster. + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/config.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/config.md new file mode 100644 index 000000000..cc32a6aca --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/config.md @@ -0,0 +1,35 @@ +# Archivo de configuración + +Sólo hay un lugar donde la configuración de Flarum no puede ser modificada a través del panel de administración de Flarum (excluyendo la base de datos), y es el archivo `config.php` ubicado en la raíz de su instalación de Flarum. + +Este archivo, aunque pequeño, contiene detalles que son cruciales para que su instalación de Flarum funcione. + +Si el archivo existe, le dice a Flarum que ya ha sido instalado. También proporciona a Flarum información de la base de datos y más. + +Aquí hay un rápido resumen de lo que significa todo con un archivo de ejemplo: + +```php + false, // activa o desactiva el modo de depuración, utilizado para solucionar problemas + 'offline' => false, // enables or disables site maintenance mode. This makes your site inaccessible to all users (including admins). + 'database' => + array ( + 'driver' => 'mysql', // el controlador de la base de datos, es decir, MySQL, MariaDB... + 'host' => 'localhost', // el host de la conexión, localhost en la mayoría de los casos, a menos que se utilice un servicio externo + 'database' => 'flarum', // el nombre de la base de datos en la instancia + 'username' => 'root', // nombre de usuario de la base de datos + 'password' => '', // contraseña de la base de datos + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', // el prefijo de las tablas, útil si se comparte la misma base de datos con otro servicio + 'port' => '3306', // el puerto de la conexión, por defecto 3306 con MySQL + 'strict' => false, + ), + 'url' => 'https://flarum.localhost', // la configuración de la URL, deberá cambiarla si cambia de dominio + 'paths' => + array ( + 'api' => 'api', // /api va a la API + 'admin' => 'admin', // /admin va a la administración + ), +); +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/console.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/console.md new file mode 100644 index 000000000..d5efd357a --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/console.md @@ -0,0 +1,77 @@ +# Consola + +Además del panel de administración, Flarum proporciona varios comandos de consola para ayudar a gestionar su foro a través de la terminal. + +Using the console: + +1. `ssh` en el servidor donde está alojada su instalación de flarum +2. `cd` to the folder that contains the file `flarum` +3. Ejecute el comando mediante `php flarum [comando]` + +## Comandos por defecto + +### list + +Lista todos los comandos de gestión disponibles, así como las instrucciones para utilizar los comandos de gestión + +### help + +`php flarum help [command_name]` + +Muestra la ayuda de un comando determinado. + +También puede mostrar la ayuda en otros formatos utilizando la opción --format: + +`php flarum help --format=xml list` + +Para mostrar la lista de comandos disponibles, utilice el comando list. + +### info + +`php flarum info` + +Get information about Flarum's core and installed extensions. Esto es muy útil para la depuración de problemas, y debe ser compartido cuando se solicita apoyo. + +### cache:clear + +`php flarum cache:clear` + +Borra la caché del backend de Flarum, incluyendo los js/css generados, la caché del formateador de texto y las traducciones en caché. Esto debe ser ejecutado después de instalar o eliminar extensiones, y ejecutar esto debe ser el primer paso cuando se producen problemas. + +### assets:publish + +`php flarum assets:publish` + +Publish assets from core and extensions (e.g. compiled JS/CSS, bootstrap icons, logos, etc). This is useful if your assets have become corrupted, or if you have switched [filesystem drivers](extend/filesystem.md) for the `flarum-assets` disk. + +### migrate + +`php flarum migrate` + +Ejecuta todas las migraciones pendientes. Debe utilizarse cuando se añade o actualiza una extensión que modifica la base de datos. + +### migrate:reset + +`php flarum migrate:reset --extension [extension_id]` + +Restablece todas las migraciones de una extensión. Esto es utilizado principalmente por los desarrolladores de extensiones, pero en ocasiones, puede ser necesario ejecutar este comando si se está eliminando una extensión, y desea borrar todos sus datos de la base de datos. Tenga en cuenta que la extensión en cuestión debe estar instalada (pero no necesariamente activada) para que esto funcione. + +### schedule:run + +`php flarum schedule:run` + +Many extensions use scheduled jobs to run tasks on a regular interval. This could include database cleanups, posting scheduled drafts, generating sitemaps, etc. If any of your extensions use scheduled jobs, you should add a [cron job](https://ostechnix.com/a-beginners-guide-to-cron-jobs/) to run this command on a regular interval: + +``` +* * * * * cd /path-to-your-flarum-install && php flarum schedule:run >> /dev/null 2>&1 +``` + +This command should generally not be run manually. + +Note that some hosts do not allow you to edit cron configuration directly. In this case, you should consult your host for more information on how to schedule cron jobs. + +### schedule:list + +`php flarum schedule:list` + +This command returns a list of scheduled commands (see `schedule:run` for more information). This is useful for confirming that commands provided by your extensions are registered properly. This **can not** check that cron jobs have been scheduled successfully, or are being run. \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md new file mode 100644 index 000000000..7b17fc28e --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md @@ -0,0 +1,26 @@ +# Docs and Translation + +## Add Documentation + +Adding documentation can help countless future Flarum users. A few ideas of what to work on: + +- User guides to help Flarum end users with some advanced Flarum features. +- More [frequently asked questions](faq.md). +- Expanded [troubleshooting](troubleshoot.md) steps. +- Step-by-step tutorials for Flarum development or installation. +- [Technical reference guides](extend/README.md) for extension developers. +- Improving literally anything else you think we should elaborate on or explain better. + +A good way to find topics to write about is to look for common questions in the [support tag](https://discuss.flarum.org/t/support) of our community. + +## Translate Flarum + +We want Flarum to be accessible to everyone, regardless of language! By contributing translations, you make it possible for many more people to enjoy Flarum. Best of all, we use user-friendly GUIs for translations, so no technical skills are necessary to help! + +Translations for Flarum core, bundled extensions, and community extensions are managed through [Weblate](https://weblate.rob006.net/projects/flarum/). + +Translations for this documentation are managed through [Crowdin](https://crowdin.com/project/flarum-docs). + +The Flarum Foundation has created the "flarum-lang" organization to support translators and ensure continuous availability of language packs. You can learn more about this by [visiting the GitHub repository](https://github.com/flarum-lang/about). + +If you want to support an existing language pack, start a new translation, or you run into issues using weblate or crowdin, it's best to [get in touch with the `flarum-lang` team](https://discuss.flarum.org/d/27519-the-flarum-language-project). diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/contributing.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/contributing.md new file mode 100644 index 000000000..abf602d77 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/contributing.md @@ -0,0 +1,170 @@ +# Contribuir + +¿Estás interesado en contribuir al desarrollo de Flarum? That's great! ¡Genial! Desde [abrir un informe de error](bugs.md) hasta crear un pull request: toda contribución es apreciada y bienvenida. Flarum wouldn't be possible without our community contributions. + +Antes de contribuir, por favor lee el [código de conducta](code-of-conduct.md). + +Este documento es una guía para los desarrolladores que quieren contribuir con código a Flarum. Si estás empezando, te recomendamos que leas la documentación de [Cómo Empezar](/extend/start.md) en los documentos de Extensión para entender un poco más cómo funciona Flarum. + +## En qué trabajar + +⚡ **Have Real Impact.** There are thousands of Flarum instances, with millions of aggregate end users. By contributing to Flarum, your code will have a positive impact on all of them. + +🔮 **Shape the Future of Flarum.** We have a long backlog, and limited time. If you're willing to champion a feature or change, it's much more likely to happen, and you'll be able to enact your vision for it. Plus, our roadmap and milestones are set by our [core development team](https://flarum.org/team), and all of us started as contributors. The best road to influence is contributing. + +🧑‍💻 **Become a Better Engineer.** Our codebase is modern, and we heavily value good engineering and clean code. There's also a lot of interesting, challenging problems to solve regarding design, infrastructure, performance, and extensibility. Especially if you're a student or early in your career, working on Flarum is a great opportunity to build development skills. + +🎠 **It's Fun!** We really enjoy working on Flarum: there's a lot of interesting challenges and fun features to build. We also have an active community on [our forums](https://discuss.flarum.org) and [Discord server](https://flarum.org/chat). + +## Configuración de desarrollo + +Consulta nuestros próximos [Hitos](https://github.com/flarum/core/milestones) para tener una visión general de lo que hay que hacer. Consulta la etiqueta [Good first issue](https://github.com/flarum/core/labels/Good%20first%20issue) para ver una lista de temas que deberían ser relativamente fáciles de empezar. If there's anything you're unsure of, don't hesitate to ask! All of us were just starting out once. + +Si estás planeando seguir adelante y trabajar en algo, por favor comenta en el tema correspondiente o primero crea uno nuevo. De esta manera podemos asegurarnos de que tu precioso trabajo no sea en vano. + +Since Flarum is so extension-driven, we highly recommend [our extension docs](extend/README.md) as a reference when working on core, as well as for bundled extensions. You should start with [the introduction](extend/README.md) for a better understanding of our extension philosophy. + +## Flujo de desarrollo + +### Setting Up a Local Codebase + +[flarum/flarum](https://github.com/flarum/flarum) is a "skeleton" application which uses Composer to download the core package and a bunch of extensions. Source code for Flarum core, extensions, and all packages used by the aforementioned is located in the Flarum monorepo [flarum/framework](https://github.com/flarum/framework). In order to contribute to these, you'll need to fork and clone the monorepo repository locally, and then add it to your dev environment as a [Composer path repository](https://getcomposer.org/doc/05-repositories.md#path): + +```bash +git clone https://github.com/flarum/flarum.git +cd flarum + +# Or, when you want to clone directly into the current directory +git clone https://github.com/flarum/flarum.git . +# Note, the directory must be empty + +# Set up a Composer path repository for Flarum monorepo packages +composer config repositories.0 path "PATH_TO_MONOREPO/*/*" +git clone https://github.com//framework.git PATH_TO_MONOREPO +``` + +Un flujo de trabajo de contribución típico es el siguiente: + +Finalmente, ejecute `composer install` para completar la instalación desde los repositorios de la ruta. + +Una vez que su instalación local esté configurada, asegúrese de que ha habilitado el modo `debug` en **config.php**, y establezca `display_errors` a `On` en su configuración php. Esto le permitirá ver los detalles de los errores tanto de Flarum como de PHP. Debug mode also forces a re-compilation of Flarum's asset files on each request, removing the need to call `php flarum cache:clear` after each change to the extension's JavaScript or CSS. + +El código del front-end de Flarum está escrito en ES6 y transpilado en JavaScript. During development you will need to recompile the JavaScript using [Node.js](https://nodejs.org/) and [`yarn`](https://yarnpkg.com/). **Please do not commit the resulting `dist` files when sending PRs**; this is automatically taken care of when changes are merged into the `main` branch. + +To contribute to the frontend, first install the JavaScript dependencies. The monorepo uses [yarn workspaces](https://classic.yarnpkg.com/lang/en/docs/workspaces/) to easily install JS dependencies across all packages within. + +```bash +cd packages/framework +yarn install +``` + +Then you can watch JavaScript files for changes during development: + +```bash +cd framework/core/js +yarn dev +``` + +The process is the same for extensions. + +```bash +cd extensions/tags/js +yarn dev +``` + +### Development Tools + +After you've forked and cloned the repositories you'll be working on, you'll need to set up local hosting so you can test out your changes. Flarum doesn't currently come with a development server, so you'll need to set up Apache/NGINX/Caddy/etc to serve this local Flarum installation. + +Alternatively, you can use tools like, [Laravel Valet](https://laravel.com/docs/master/valet) (Mac), [XAMPP](https://www.apachefriends.org/index.html) (Windows), or [Docker-Flarum](https://github.com/mondediefr/docker-flarum) (Linux) to serve a local forum. + +Most Flarum contributors develop with [PHPStorm](https://www.jetbrains.com/phpstorm/download/) or [Visual Studio Code](https://code.visualstudio.com/). + +## Estilo de Codificación + +A typical contribution workflow looks like this: + +0. 🌳 Se bifurca el **Branch** apropiado en un nuevo branch de características. + * *Correcciones de Bugs* debe enviarse al ultimo branch estable. + * Características *menores* que son totalmente compatibles con la versión actual de Flarum pueden ser enviadas al ultimo branch estable. + +1. 🔨 **Escribe** algo de código. + * Ver abajo sobre el [Estilo de codificación](#coding-style). + * Características *mayores* deben enviarse siempre al branch `master`, que contiene la próxima versión de Flarum. + * *Major* features should always be sent to the `main` branch, which contains the upcoming Flarum release. + * Internamente utilizamos el scheme de nomenclatura `/` (eg. `tz/refactor-frontend`). + +2. 🚦 **Prueba** el código. + * Añade pruebas unitarias según sea necesario cuando arregles errores o añadas características. + +3. 💾 Haz el **commit** de su código con un mensaje descriptivo. + * Si su cambio resuelve un problema existente (por lo general, debería) incluir "Fixes #123" en una nueva línea, donde 123 es el número del issue. + * Escriba un [buen mensaje en el commit](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). + * See [here](extend/testing.md) for more information about testing in Flarum. + +4. 🎁 **Envia** un Pull Request en GitHub. + * Rellene la plantilla del pull request. + * Follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) specification. + * *Fix* commits should describe the issue fixed, not how it was fixed. + +5. 🤝 **Intercambio** con el equipo de Flarum para su aprobación. + * Fill out the pull request template. + * Cuando se aborda la retroalimentación, envíe commits adicionales en lugar de sobrescribir o aplastar (vamos a aplastar en la fusión). + * NO registre los archivos `dist` de JavaScript. Éstos se compilarán automáticamente en el merge. + +6. 🕺 **Baila** como si acabaras de contribuir a Flarum. + * Los miembros del equipo revisarán su código. Podemos sugerir algunos cambios o mejoras o alternativas, pero para los pequeños cambios su pull request debería ser aceptado rápidamente. + * When addressing feedback, push additional commits instead of overwriting or squashing (we will squash on merge). + +7. **Columnas** deben nombrarse según su tipo de datos: + +## Herramientas de Desarrollo + +In order to keep the Flarum codebase clean and consistent, we have a number of coding style guidelines that we follow. When in doubt, read the source code. + +Don't worry if your code styling isn't perfect! StyleCI and Prettier will automatically check formatting for every pull request. This allows us to focus on the content of the contribution, not the code style. + +### PHP + +Flarum follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) coding standard and the [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) autoloading standard. On top of this, we conform to a number of [other style rules](https://github.com/flarum/framework/blob/main/.styleci.yml). We use PHP 7 type hinting and return type declarations where possible, and [PHPDoc](https://docs.phpdoc.org/) to provide inline documentation. Try and mimic the style used by the rest of the codebase in your contributions. + +* Los espacios de nombres deben ser singulares (p. ej. `Flarum-Discussion`, no `Flarum-Discussions`). +* Las interfaces deben llevar el sufijo `Interface` (p. ej. `MailableInterface`) +* Las clases abstractas deben llevar el prefijo `Abstract` (p. ej. `AbstractModel`) +* Los rasgos deben llevar el sufijo `Trait` (p. ej. `ScopeVisibilityTrait`) + +### JavaScript + +Flarum's JavaScript mostly follows the [Airbnb Style Guide](https://github.com/airbnb/javascript). We use [ESDoc](https://esdoc.org/manual/tags.html) to provide inline documentation. + +### Traducciones + +**Columns** should be named according to their data type: +* DATETIME o TIMESTAMP: `{verbed}_at` (ej. created_at, read_at) o `{verbed}_until` (ej. suspended_until) +* INT que es un recuento: `{noun}_count` (ej. comment_count, word_count) +* Clave foránea: `{verbed}_{entity}_id` (ej. hidden_user_id) + * Se puede omitir el término para la relación primaria (por ejemplo, el autor del post es sólo `user_id`) +* BOOL: `is_{adjective}` (ej. is_locked) + +**Tables** should be named as follows: +* Utilizar la forma plural (`discussions`) +* Separe las palabras múltiples con guiones bajos (`access_tokens`) +* Para las tablas de relaciones, unir los dos nombres de las tablas en singular con un guión bajo en orden alfabético (ej. `discussion_user`) + +### CSS + +Flarum's CSS classes roughly follow the [SUIT CSS naming conventions](https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md) using the format `.ComponentName-descendentName--modifierName`. + +### Translations + +We use a [standard key format](/extend/i18n.md#appendix-a-standard-key-format) to name translation keys descriptively and consistently. + +## Acuerdo de Licencia para Colaboradores + +By contributing your code to Flarum you grant the Flarum Foundation (Stichting Flarum) a non-exclusive, irrevocable, worldwide, royalty-free, sublicensable, transferable license under all of Your relevant intellectual property rights (including copyright, patent, and any other rights), to use, copy, prepare derivative works of, distribute and publicly perform and display the Contributions on any licensing terms, including without limitation: (a) open source licenses like the MIT license; and (b) binary, proprietary, or commercial licenses. Except for the licenses granted herein, You reserve all right, title, and interest in and to the Contribution. + +You confirm that you are able to grant us these rights. You represent that You are legally entitled to grant the above license. If Your employer has rights to intellectual property that You create, You represent that You have received permission to make the Contributions on behalf of that employer, or that Your employer has waived such rights for the Contributions. + +You represent that the Contributions are Your original works of authorship, and to Your knowledge, no other person claims, or has the right to claim, any right in any invention or patent related to the Contributions. You also represent that You are not legally obligated, whether by entering into an agreement or otherwise, in any way that conflicts with the terms of this license. + +The Flarum Foundation acknowledges that, except as explicitly described in this Agreement, any Contribution which you provide is on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/current.json b/i18n/es/docusaurus-plugin-content-docs/version-1.x/current.json new file mode 100644 index 000000000..4e26ceae4 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/current.json @@ -0,0 +1,42 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.guideSidebar.category.Introduction": { + "message": "Introducción", + "description": "The label for category Introduction in sidebar guideSidebar" + }, + "sidebar.guideSidebar.category.Setting Up": { + "message": "Configuración", + "description": "The label for category Setting Up in sidebar guideSidebar" + }, + "sidebar.guideSidebar.category.Management": { + "message": "Gestión", + "description": "The label for category Management in sidebar guideSidebar" + }, + "sidebar.guideSidebar.category.Advanced": { + "message": "Advanced", + "description": "The label for category Advanced in sidebar guideSidebar" + }, + "sidebar.extendSidebar.category.Main Concepts": { + "message": "Conceptos Principales", + "description": "The label for category Main Concepts in sidebar extendSidebar" + }, + "sidebar.extendSidebar.category.Reference Guides": { + "message": "Guías de Referencia", + "description": "The label for category Reference Guides in sidebar extendSidebar" + }, + "sidebar.extendSidebar.category.Advanced Guides": { + "message": "Guías Avanzadas", + "description": "The label for category Advanced Guides in sidebar extendSidebar" + }, + "sidebar.extendSidebar.category.Update Guides": { + "message": "Update Guides", + "description": "The label for category Update Guides in sidebar extendSidebar" + }, + "sidebar.internalSidebar.category.Internal Docs": { + "message": "Internal Docs", + "description": "The label for category Internal Docs in sidebar internalSidebar" + } +} \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/README.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/README.md new file mode 100644 index 000000000..b5361960b --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/README.md @@ -0,0 +1,40 @@ +- - - +slug: /extend +- - - + +# Extensión de Flarum + +Flarum es minimalista, pero también es altamente extensible. De hecho, ¡la mayoría de las características que vienen con Flarum son en realidad extensiones! + +Este enfoque hace que Flarum sea extremadamente personalizable. Un usuario puede desactivar cualquier característica que no utilice en su foro, e instalar otras extensiones para hacer un foro perfecto para su comunidad. + +Para lograr esta extensibilidad, Flarum ha sido construido con ricas APIs y puntos de extensión. Con algunos conocimientos de programación, puedes aprovechar estas APIs para añadir casi cualquier característica que desees. Esta sección de la documentación pretende enseñarte cómo funciona Flarum, y cómo usar las APIs para que puedas construir tus propias extensiones. + +## Core vs. Extensiones + +¿Dónde trazamos la línea entre el core de Flarum y sus extensiones? ¿Por qué algunas características se incluyen en el core y otras no? Es importante entender esta distinción para que podamos mantener la consistencia y la calidad dentro del ecosistema de Flarum. + +**El core de Flarum** no pretende estar lleno de características. Más bien, es un andamio, o un marco, que proporciona una base fiable sobre la que se pueden construir extensiones. Contiene sólo las funcionalidades básicas, no opinables, que son esenciales para un foro: discusiones, mensajes, usuarios, grupos y notificaciones. + +**Las extensiones incluidas** son características que vienen empaquetadas con Flarum y están activadas por defecto. Son extensiones como cualquier otra, y pueden ser desactivadas y desinstaladas. Si bien su alcance no pretende abordar todos los casos de uso, la idea es hacerlas lo suficientemente genéricas y configurables para que puedan satisfacer a la mayoría. + +**Las extensiones de terceros** son características creadas por otros y no están oficialmente soportadas por el equipo de Flarum. Pueden ser construidas y usadas para abordar casos de uso más específicos. + +Si quieres solucionar un error o una deficiencia del núcleo, o de una extensión ya existente, puede ser apropiado *contribuir al proyecto respectivo* en lugar de dispersar el esfuerzo en una nueva extensión de terceros. Es una buena idea comenzar una discusión en la [Comunidad Flarum](https://discuss.flarum.org/) para obtener la perspectiva de los desarrolladores de Flarum. + +## Recursos útiles + +- [Esta documentación](start.md) +- [Consejos para desarrolladores principiantes](https://discuss.flarum.org/d/5512-extension-development-tips) +- [Desarrolladores explicando su flujo de trabajo para el desarrollo de extensiones](https://github.com/flarum/cli) +- [Consejos sobre el espacio de nombres de las extensiones](https://discuss.flarum.org/d/6320-extension-developers-show-us-your-workflow) +- [Documentación de Mithril js](https://discuss.flarum.org/d/9625-flarum-extension-namespacing-tips) +- [Documentación de la API de Laravel](https://mithril.js.org/) +- [Documentación de la API de Flarum](https://laravel.com/api/8.x/) +- [Flarum API Docs](https://api.flarum.org) +- [ES6 cheatsheet](https://github.com/DrkSephy/es6-cheatsheet) + +### Obtener ayuda + +- [Comunidad oficial de desarrollo de Flarum](https://discuss.flarum.org/t/dev) +- [Únase a nosotros en #extend en nuestro chat de Discord](https://flarum.org/discord/) diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/admin.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/admin.md new file mode 100644 index 000000000..cad6292c7 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/admin.md @@ -0,0 +1,217 @@ +# Panel de Administración + +La Beta 15 ha introducido un panel de administración y una API frontend completamente rediseñada. Ahora es más fácil que nunca añadir ajustes o permisos a tu extensión. + +Antes de la Beta 15, los ajustes de las extensiones se añadían en un `SettingsModal` o se añadía una nueva página para ajustes más complejos. Ahora, cada extensión tiene una página que contiene información, ajustes y los propios permisos de la extensión. + +Puedes simplemente registrar los ajustes, extender la base [`ExtensionPage`] (https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage), o proporcionar tu propia página completamente personalizada. + +## API de datos de la extensión + +Esta nueva API le permite añadir ajustes a su extensión con muy pocas líneas de código. + +### Cómo informar a la API sobre su extensión + +Antes de que puedas registrar nada, tienes que decirle a `ExtensionData` de qué extensión va a obtener datos. + +Simplemente ejecute la función `for` en `app.extensionData` pasando el id de su extensión. Para encontrar el id de tu extensión, toma el nombre del compositor y sustituye las barras por guiones (ejemplo: 'fof/merge-discussions' se convierte en 'fof-merge-discussions'). Extensions with the `flarum-` and `flarum-ext-` will omit those from the name (example: 'webbinaro/flarum-calendar' becomes 'webbinaro-calendar'). + +Para el siguiente ejemplo, utilizaremos la extensión ficticia 'acme/interstellar': + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') +}); +``` + +Una vez hecho esto, puedes empezar a añadir configuraciones y permisos. + +:::info Note + +Todas las funciones de registro en `ExtensionData` son encadenables, lo que significa que puedes llamarlas una tras otra sin tener que volver a ejecutar `for`. + +::: + +### Registro de ajustes + +Se recomienda añadir campos de configuración para los elementos simples. Como regla general, si sólo necesitas almacenar cosas en la tabla de ajustes, esto debería ser suficiente para ti. + +Para añadir un campo, llama a la función `registerSetting` después de `for` en `app.extensionData` y pasa un 'setting object' como primer argumento. Detrás de las escenas `ExtensionData` en realidad convierte su configuración en un [`ItemList`](https://api.docs.flarum.org/js/master/class/src/common/utils/itemlist.ts~itemlist), puede pasar un número de prioridad como el segundo argumento. + +Aquí hay un ejemplo con un elemento switch (booleano): + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerSetting( + { + setting: 'acme-interstellar.coordinates', // Esta es la clave con la que se guardarán los ajustes en la tabla de ajustes de la base de datos. + label: app.translator.trans('acme-interstellar.admin.coordinates_label'), // La etiqueta que se mostrará para que el administrador sepa lo que hace el ajuste. + type: 'boolean', // Qué tipo de ajuste es, las opciones válidas son: booleano, texto (o cualquier otro tipo de etiqueta ), y seleccionar. + }, + 30 // Opcional: + Prioridad + ) +}); +``` + +Si se utiliza `type: 'select'` el objeto de ajuste tiene un aspecto un poco diferente: + +```js +{ + setting: 'acme-interstellar.fuel_type', + label: app.translator.trans('acme-interstellar.admin.fuel_type_label'), + type: 'select', + options: { + 'LOH': 'Liquid Fuel', // La clave en este objeto es lo que la configuración almacenará en la base de datos, el valor es la etiqueta que el administrador verá (recuerde usar traducciones si tienen sentido en su contexto). + 'RDX': 'Solid Fuel', + }, + default: 'LOH', +} +``` + +Also, note that additional items in the setting object will be used as component attrs. This can be used for placeholders, min/max restrictions, etc: + +```js +{ + setting: 'acme-interstellar.crew_count', + label: app.translator.trans('acme-interstellar.admin.crew_count_label'), + type: 'number', + min: 1, + max: 10 +} +``` + +Si quieres añadir algo a los ajustes como algún texto extra o una entrada más complicada, también puedes pasar una devolución de llamada como primer argumento que devuelva JSX. Este callback se ejecutará en el contexto de [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) y los valores de configuración no se serializarán automáticamente. + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerSetting(function () { + if (app.session.user.username() === 'RocketMan') { + + return ( +
+

{app.translator.trans('acme-interstellar.admin.you_are_rocket_man_label')}

+ +
+ ); + } + }) +}); +``` + +### Registro de Permisos + +Como novedad en la beta 15, los permisos pueden encontrarse ahora en dos lugares. Ahora, puedes ver los permisos individuales de cada extensión en su página. Todos los permisos se pueden seguir encontrando en la página de permisos. + +Para que esto ocurra, los permisos deben estar registrados en `ExtensionData`. Esto se hace de forma similar a la configuración, llamando a `registerPermission`. + +Volvemos a nuestra extensión favorita del rocket: + * Objeto de permiso + * Qué tipo de permiso - ver las funciones de [`PermissionGrid`](https://api.docs.flarum.org/js/master/class/src/admin/components/permissiongrid.js~permissiongrid) para los tipos (eliminar elementos del nombre) + * Prioridad de `ItemList` + +Recuerda que todas estas funciones se pueden encadenar como: + +```js +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerPermission( + { + icon: 'fas fa-rocket', // Icono Font-Awesome + label: app.translator.trans('acme-interstellar.admin.permissions.fly_rockets_label'), // Etiqueta de permiso + permission: 'discussion.rocket_fly', // Nombre real del permiso almacenado en la base de datos (y utilizado al comprobar el permiso). + tagScoped: true, // Si es posible aplicar este permiso en las etiquetas, no sólo globalmente. Se explica en el siguiente párrafo. + }, + 'start', // El permiso de la categoría se añadirá a la cuadrícula (grid) + 95 // Opcional: Prioridad + ); +}); +``` + +If your extension interacts with the [tags extension](https://github.com/flarum/tags) (which is fairly common), you might want a permission to be tag scopable (i.e. applied on the tag level, not just globally). You can do this by including a `tagScoped` attribute, as seen above. Permissions starting with `discussion.` will automatically be tag scoped unless `tagScoped: false` is indicated. + +Crea una nueva clase que extienda el componente `Page` o `ExtensionPage`: + +### Recordatorio de Encadenamiento + +Entonces, simplemente ejecute `registerPage`: + +```js +app.extensionData + .for('acme-interstellar') + .registerSetting(...) + .registerSetting(...) + .registerPermission(...) + .registerPermission(...); + .registerSetting(...) + .registerPermission(...) + .registerPermission(...); +``` + +### Extending/Overriding de la Página por Defecto + +A veces tienes configuraciones más complicadas que se mezclan con las relaciones, o simplemente quieres que la página se vea completamente diferente. En este caso, necesitarás decirle a `ExtensionData` que quieres proporcionar tu propia página. Note that `buildSettingComponent`, the util used to register settings by providing a descriptive object, is available as a method on `ExtensionPage` (extending from `AdminPage`, which is a generic base for all admin pages with some util methods). + +¡Puedes extender la [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) o extender la `Page` base y diseñar la tuya propia! + +```js +import ExtensionPage from 'flarum/components/ExtensionPage'; + +export default class StarPage extends ExtensionPage { + content() { + return ( +

¡Hola desde la sección de ajustes!

+ ) + } +} + +``` + +En la beta 15, las páginas de las extensiones tienen espacio para información extra que se extrae del composer.json de las extensiones. + +```js + +import StarPage from './components/StarPage'; + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerPage(StarPage); +}); +``` + +Para más información, consulte el esquema [composer.json](https://getcomposer.org/doc/04-schema.md). + +You can extend the [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) or extend the base `Page` and design your own! + +## Metadatos del Composer.json + +En la beta 15, las páginas de las extensiones tienen espacio para información extra que se extrae del composer.json de las extensiones. + +Para más información, consulte el esquema (schema) [composer.json](https://getcomposer.org/doc/04-schema.md). + +| Descripción | Dónde en composer.json | +| -------------------------------------- | --------------------------------------------------------------------- | +| Enlace de discusión discuss.flarum.org | Clave "forum" dentro de "support" | +| Documentación | Clave "docs" dentro de "support" | +| Soporte (correo electrónico) | Clave "email" dentro de "support" | +| Sitio web | Clave "homepage" | +| Donación | Bloque de claves "funding" (Nota: Sólo se utilizará el primer enlace) | +| Fuente | Clave "source" dentro de "support" | diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md new file mode 100644 index 000000000..8d776b680 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md @@ -0,0 +1,62 @@ +# Aceleración de la API + +Flarum viene con un `Flarum\Api\Middleware\ThrottleApi` [middleware](middleware.md) para acelerar las peticiones a la API. Esto se ejecuta en cada ruta de la API, y las extensiones pueden añadir su propia lógica personalizada para acelerar las solicitudes. + +:::caution Rutas del Foro + +Algunas rutas del foro (inicio de sesión, registro, olvido de contraseña, etc) funcionan llamando a una ruta de la API bajo la superficie. El middleware `ThrottleApi` no se ejecuta actualmente para estas peticiones, pero está previsto para el futuro. + +::: + +## Aceleradores personalizados + +El formato de un acelerador personalizado es extremadamente simple: todo lo que necesitas es un cierre o clase invocable que tome la petición actual como argumento, y devuelva una de las siguientes opciones + +- `false`: Esto evita explícitamente el aceleramiento para esta solicitud, anulando todos los demás aceleradores. +- `true`: Esto marca la solicitud como para ser acelerada. +- `null`: Esto significa que este acelerador no se aplica. Cualquier otra salida será ignorada, con el mismo efecto que `null`. + +Los aceleradores se ejecutarán en TODAS las peticiones, y son responsables de averiguar si se aplican o no. Por ejemplo, considere el acelerador de correos de Flarum: + +```php +use DateTime; +use Flarum\Post\Post; + +function ($request) { + if (! use DateTime; +use Flarum\Post\Post; + +function ($request) { + if (! in_array($request->getAttribute('routeName'), ['discussions.create', 'posts.create'])) { + return; + } + + $actor = $request->getAttribute('actor'); + + if ($actor->can('postWithoutThrottle')) { + return false; + } + + if (Post::where('user_id', $actor->id)->where('created_at', '>=', new DateTime('-10 seconds'))->exists()) { + return true; + } +}; +``` + +Los aceleradores pueden ser añadidos o eliminados a través del middleware `ThrottleApi` en `extend.php`. Por ejemplo: + +```php +set('throttleAll', function () { + return false; + }) + ->remove('bypassThrottlingAttribute'), + // Other extenders +]; +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/api.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/api.md new file mode 100644 index 000000000..06d35f1cc --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/api.md @@ -0,0 +1,353 @@ +# API and Data Flow + +In the [previous article](models.md), we learned how Flarum uses models to interact with data. Here, we'll learn how to get that data from the database to the JSON-API to the frontend, and all the way back again. + +:::info + +To use the built-in REST API as part of an integration, see [Consuming the REST API](../rest-api.md). + +::: + +## Ciclo de vida de las solicitudes de la API + +Before we go into detail about how to extend Flarum's data API, it's worth thinking about the lifecycle of a typical API request: + +![Flarum API Flowchart](/en/img/api_flowchart.png) + +1. Se envía una solicitud HTTP a la API de Flarum. Normalmente, esto vendrá del frontend de Flarum, pero los programas externos también pueden interactuar con la API. La API de Flarum sigue en su mayoría la especificación [JSON:API](https://jsonapi.org/), por lo que, en consecuencia, las solicitudes deben seguir [dicha especificación](https://jsonapi.org/format/#fetching). +2. La solicitud se ejecuta a través de [middleware](middleware.md), y se dirige al controlador adecuado. Puedes aprender más sobre los controladores en su conjunto en nuestra [documentación sobre rutas y contenido](routes.md). Asumiendo que la petición es a la API (que es el caso de esta sección), el controlador que maneja la petición será una subclase de `Flarum\Api\AbstractSerializeController`. +3. Cualquier modificación realizada por las extensiones del controlador a través del extensor [`ApiController`] (#extending-api-controllers) se aplica. Esto podría suponer el cambio de sort, añadir includes, cambiar el serializador, etc. +4. Se llama al método `$this->data()` del controlador, obteniendo algunos datos en bruto que deben ser devueltos al cliente. Típicamente, estos datos tomarán la forma de una colección o instancia del modelo de Laravel Eloquent, que ha sido recuperada de la base de datos. Dicho esto, los datos pueden ser cualquier cosa siempre que el serializador del controlador pueda procesarlos. Cada controlador es responsable de implementar su propio método `data`. Ten en cuenta que para las peticiones `PATCH`, `POST` y `DELETE`, `data` realizará la operación en cuestión, y devolverá la instancia del modelo modificado. +5. Esos datos se ejecutan a través de cualquier callback de preserialización que las extensiones registren a través del extensor [`ApiController`](#extending-api-controllers). +6. Los datos se pasan a través de un [serializador](#serializers), que los convierte del formato de base de datos del backend al formato JSON: API esperado por el frontend. También adjunta cualquier objeto relacionado, que se ejecuta a través de sus propios serializadores. Como explicaremos más adelante, las extensiones pueden [añadir / anular relaciones y atributos](#attributes-and-relationships) en el nivel de serialización. +7. Los datos serializados se devuelven como una respuesta JSON al frontend. +8. Si la solicitud se originó a través de la `Store` del frontend de Flarum, los datos devueltos (incluyendo cualquier objeto relacionado) serán almacenados como [modelos del frontend](#frontend-models) en el almacén del frontend. + +## API Endpoints + +We learned how to use models to interact with data, but we still need to get that data from the backend to the frontend. We do this by writing API Controller [routes](routes.md), which implement logic for API endpoints. + +As per the JSON:API convention, we'll want to add separate endpoints for each operation we support. Common operations are: + +- Listing instances of a model (possibly including searching/filtering) +- Getting a single model instance +- Creating a model instance +- Updating a model instance +- Deleting a single model instance + +We'll go over each type of controller shortly, but once they're written, you can add these five standard endpoints (or a subset of them) using the `Routes` extender: + +```php + (new Extend\Routes('api')) + ->get('/tags', 'tags.index', ListTagsController::class) + ->get('/tags/{id}', 'tags.show', ShowTagController::class) + ->post('/tags', 'tags.create', CreateTagController::class) + ->patch('/tags/{id}', 'tags.update', UpdateTagController::class) + ->delete('/tags/{id}', 'tags.delete', DeleteTagController::class) +``` + +:::caution + +Paths to API endpoints are not arbitrary! To support interactions with frontend models: + +- The path should either be `/prefix/{id}` for get/update/delete, or `/prefix` for list/create. +- the prefix (`tags` in the example above) must correspond to the JSON:API model type. You'll also use this model type in your serializer's `$type` attribute, and when registering the frontend model (`app.store.models.TYPE = MODEL_CLASS`). +- The methods must match the example above. + +Also, remember that route names (`tags.index`, `tags.show`, etc) must be unique! + +::: + +The `Flarum\Api\Controller` namespace contains a number of abstract controller classes that you can extend to easily implement your JSON-API resources. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically create your endpoint controllers: +```bash +$ flarum-cli make backend api-controller +``` + +::: + +### Listado de recursos + +For the controller that lists your resource, extend the `Flarum\Api\Controller\AbstractListController` class. At a minimum, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a collection of models. The `data` method accepts the `Request` object and the tobscure/json-api `Document`. + +```php +use Flarum\Api\Controller\AbstractListController; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ListTagsController extends AbstractListController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + return Tag::all(); + } +} +``` + +#### Paginación + +You can allow the number of resources being **listed** to be customized by specifying the `limit` and `maxLimit` properties on your controller: + +```php + // The number of records included by default. + public $limit = 20; + + // The maximum number of records that can be requested. + public $maxLimit = 50; +``` + +You can then extract pagination information from the request using the `extractLimit` and `extractOffset` methods: + +```php +$limit = $this->extractLimit($request); +$offset = $this->extractOffset($request); + +return Tag::skip($offset)->take($limit); +``` + +To add pagination links to the JSON:API document, use the `Document::addPaginationLinks` method. + +#### Clasificación + +You can allow the sort order of resources being **listed** to be customized by specifying the `sort` and `sortField` properties on your controller: + +```php + // The default sort field and order to use. + public $sort = ['name' => 'asc']; + + // The fields that are available to be sorted by. + public $sortFields = ['firstName', 'lastName']; +``` + +You can then extract sorting information from the request using the `extractSort` method. This will return an array of sort criteria which you can apply to your query: + +```php +use Illuminate\Support\Str; + +// ... + +$sort = $this->extractSort($request); +$query = Tag::query(); + +foreach ($sort as $field => $order) { + $query->orderBy(Str::snake($field), $order); +} + +return $query->get(); +``` + +#### Search + +Read our [searching and filtering](search.md) guide for more information! + +### Mostrar un recurso + +For the controller that shows a single resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the list controller, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a single model. We'll learn about serializers [in just a bit](#serializers). + +```php +use Flarum\Api\Controller\AbstractShowController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ShowTagController extends AbstractShowController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + return Tag::findOrFail($id); + } +} +``` + +### Creación de un recurso + +For the controller that creates a resource, extend the `Flarum\Api\Controller\AbstractCreateController` class. This is the same as the show controller, except the response status code will automatically be set to `201 Created`. You can access the incoming JSON:API document body via `$request->getParsedBody()`: + +```php +use Flarum\Api\Controller\AbstractCreateController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class CreateTagController extends AbstractCreateController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $attributes = Arr::get($request->getParsedBody(), 'data.attributes'); + + return Tag::create([ + 'name' => Arr::get($attributes, 'name') + ]); + } +} +``` + +### Actualización de un recurso + +For the controller that updates a resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the create controller, you can access the incoming JSON:API document body via `$request->getParsedBody()`. + +### Borrar un recurso + +For the controller that deletes a resource, extend the `Flarum\Api\Controller\AbstractDeleteController` class. You only need to implement a `delete` method which enacts the deletion. The controller will automatically return an empty `204 No Content` response. + +```php +use Flarum\Api\Controller\AbstractDeleteController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; + +class DeleteTagController extends AbstractDeleteController +{ + protected function delete(Request $request) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + Tag::findOrFail($id)->delete(); + } +} +``` + +### ncluir Relaciones + +To include relationships when **listing**, **showing**, or **creating** your resource, specify them in the `$include` and `$optionalInclude` properties on your controller: + +```php + // The relationships that are included by default. + public $include = ['user']; + + // Other relationships that are available to be included. + public $optionalInclude = ['discussions']; +``` + +You can then get a list of included relationships using the `extractInclude` method. This can be used to eager-load the relationships on your models before they are serialized: + +```php +$relations = $this->extractInclude($request); + +return Tag::all()->load($relations); +``` + +### Extensión de los controladores de la API + +It is possible to customize all of these options on _existing_ API controllers too via the `ApiController` extender + +```php +use Flarum\Api\Event\WillGetData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->setSerializer(MyDiscussionSerializer::class) + ->addInclude('user') + ->addOptionalInclude('posts') + ->setLimit(20) + ->setMaxLimit(50) + ->setSort(['name' => 'asc']) + ->addSortField('firstName') + ->prepareDataQuery(function ($controller) { + // Add custom logic here to modify the controller + // before data queries are executed. + }) +] +``` + +The `ApiController` extender can also be used to adjust data before serialization + +```php +use Flarum\Api\Event\WillSerializeData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->prepareDataForSerialization(function ($controller, $data, $request, $document) { + $data->load('myCustomRelation'); + }), +] +``` + +## Serializadores + +Before we can send our data to the frontend, we need to convert it to JSON:API format so that it can be consumed by the frontend. You should become familiar with the [JSON:API specification](https://jsonapi.org/format/). Flarum's JSON:API layer is powered by the [tobscure/json-api](https://github.com/tobscure/json-api) library. + +A serializer is just a class that converts some data (usually [Eloquent models](models.md#backend-models)) into JSON:API. Serializers serve as intermediaries between backend and frontend models: see the [model documentation](models.md) for more information. To define a new resource type, create a new serializer class extending `Flarum\Api\Serializer\AbstractSerializer`. You must specify a resource `$type` and implement the `getDefaultAttributes` method which accepts the model instance as its only argument: + +```php +use Flarum\Api\Serializer\AbstractSerializer; +use Flarum\Api\Serializer\UserSerializer; + +class DiscussionSerializer extends AbstractSerializer +{ + protected $type = 'discussions'; + + protected function getDefaultAttributes($discussion) + { + return [ + 'title' => $discussion->title, + ]; + } +} +``` + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically create your serializer: +```bash +$ flarum-cli make backend api-serializer +``` + +::: + +### Atributos y relaciones + +You can also specify relationships for your resource. Simply create a new method with the same name as the relation on your model, and return a call to `hasOne` or `hasMany` depending on the nature of the relationship. You must pass in the model instance and the name of the serializer to use for the related resources. + +```php + protected function user($discussion) + { + return $this->hasOne($discussion, UserSerializer::class); + } +``` + +### Extending Serializers + +To add **attributes** and **relationships** to an existing resource type, use the `ApiSerializer` extender: + +```php +use Flarum\Api\Serializer\UserSerializer; + +return [ + (new Extend\ApiSerializer(UserSerializer::class)) + // One attribute at a time + ->attribute('firstName', function ($serializer, $user, $attributes) { + return $user->first_name + }) + // Multiple modifications at once, more complex logic + ->mutate(function($serializer, $user, $attributes) { + $attributes['someAttribute'] = $user->someAttribute; + if ($serializer->getActor()->can('administrate')) { + $attributes['someDate'] = $serializer->formatDate($user->some_date); + } + + return $attributes; + }) + // API relationships + ->hasOne('phone', PhoneSerializer::class) + ->hasMany('comments', CommentSerializer::class), +] +``` + +### Non-Model Serializers and `ForumSerializer` + +Serializers don't have to correspond to Eloquent models: you can define JSON:API resources for anything. For instance, Flarum core uses the [`Flarum\Api\Serializer\ForumSerializer`](https://api.docs.flarum.org/php/master/flarum/api/serializer/forumserializer) to send an initial payload to the frontend. This can include settings, whether the current user can perform certain actions, and other data. Many extensions add data to the payload by extending the attributes of `ForumSerializer`. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/assets.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/assets.md new file mode 100644 index 000000000..16b401fc3 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/assets.md @@ -0,0 +1,7 @@ +# Extension Assets + +Some extensions might want to include assets like images or JSON files in their source code (note that this is not the same as uploads, which would probably require a [filesystem disk](filesystem.md)). + +This is actually very easy to do. Just create an `assets` folder at the root of your extension, and place any asset files there. Flarum will then automatically copy those files to its own `assets` directory (or other storage location if [one is offered by extensions](filesystem.md)) every time the extension is enabled or [`php flarum assets:publish`](../console.md) is executed. + +If using the default storage driver, assets will be available at `https://FORUM_URL/assets/extensions/EXTENSION_ID/file.path`. However, since other extensions might use remote filesystems, we recommend serializing the url to assets you need in the backend. See [Flarum's serialization of the logo and favicon URLs](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Serializer/ForumSerializer.php#L85-L86) for an example. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md new file mode 100644 index 000000000..a8bf6f5ec --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md @@ -0,0 +1,235 @@ +# Autorización + +Como todo framework, Flarum permite restringir ciertas acciones y contenidos a determinados usuarios. Hay dos sistemas paralelos para esto: + +- El proceso de autorización dicta si un usuario puede realizar una determinada acción. +- El alcance de la visibilidad puede aplicarse a una consulta de la base de datos para restringir eficazmente los registros a los que los usuarios pueden acceder. This is documented in our [model visibility](model-visibility.md) article. + +## Proceso de Autorización + +El proceso de autorización se utiliza para comprobar si una persona está autorizada a realizar ciertas acciones. Por ejemplo, queremos comprobar si un usuario está autorizado antes de que: + +- Acceda al panel de control del administrador +- Inicie un debate +- Edite un mensaje +- Actualice el perfil de otro usuario + +Cada uno de ellos está determinado por un criterio único: en algunos casos, un flag es suficiente; de lo contrario, podríamos necesitar una lógica personalizada. + +## Alcance de la visibilidad + +Las consultas de autorización se realizan con 3 parámetros, con la lógica contenida en [`Flarum\User\Gate`](https://api.docs.flarum.org/php/master/flarum/user/gate): + +1. El actor: el usuario que intenta realizar la acción +2. La habilidad: una cadena que representa la acción que el actor está intentando +3. Los argumentos: normalmente una instancia de un modelo de base de datos que es el objeto de la habilidad intentada, pero puede ser cualquier cosa. + +En primer lugar, pasamos la solicitud completa (los tres parámetros) por todas las [políticas](#policies) registradas por las extensiones y el núcleo. Las políticas son bloques de lógica proporcionados por el núcleo y las extensiones que determinan si el actor puede realizar la habilidad con los argumentos. Las políticas pueden devolver una de las siguientes cosas: + +- `Flarum\User\Access\AbstractPolicy::ALLOW` (via `$this->allow()`) +- `Flarum\User\Access\AbstractPolicy::DENY` (via `$this->deny()`) +- `Flarum\User\Access\AbstractPolicy::FORCE_ALLOW` (via `$this->forceAllow()`) +- `Flarum\User\Access\AbstractPolicy::FORCE_DENY` (via `$this->forceDeny()`) + +Los resultados de las políticas se consideran en la prioridad `FORCE_DENY` > `FORCE_ALLOW` > `DENY` > `ALLOW`. Por ejemplo, si una sola política devuelve `FORCE_DENY`, todas las demás políticas serán ignoradas. Si una política devuelve `DENY` y 10 políticas devuelven `ALLOW`, la solicitud será denegada. Esto permite tomar decisiones independientemente del orden en el que se arranquen las extensiones. Tenga en cuenta que las políticas son extremadamente poderosas: si el acceso es denegado en la etapa de políticas, eso anulará los permisos de grupo e incluso los privilegios de administrador. + +En segundo lugar, si todas las políticas devuelven null (o no devuelven nada), comprobamos si el usuario está en un grupo que tiene un permiso igual a la habilidad (nótese que tanto los permisos como las habilidades se representan como cadenas). Si es así, autorizamos la acción. Consulta nuestra [documentación sobre grupos y permisos](permissions.md) para obtener más información sobre los permisos. + +Luego, si el usuario está en el grupo de administradores, autorizaremos la acción. + +Finalmente, como hemos agotado todas las comprobaciones, asumiremos que el usuario no está autorizado y denegaremos la solicitud. + +## Autorización en el Frontend + +El sistema de autorización de Flarum es accesible a través de los métodos públicos de la clase `Flarum\User\User`. Los más importantes se enumeran a continuación; otros están documentados en nuestra [documentación de la API de PHP](https://api.docs.flarum.org/php/master/flarum/user/user). + + +En este ejemplo, usaremos `$actor` como una instancia de `Flarum\User\User`, `'viewForum'` y `'reply'` como ejemplos de habilidades, y `$discussion` (instancia de `Flarum\Discussion\Discussion`) como argumento de ejemplo. + +```php +// Comprueba si un usuario puede realizar una acción. +// ADVERTENCIA: esto debe ser utilizado con precaución, ya que no +// ejecuta el proceso de autorización, por lo que no tiene en cuenta las políticas. +$canDoSomething = $actor->can('viewForum'); + +// Comprueba si un usuario puede realizar una acción sobre un tema. +// Sin embargo, es útil para implementar políticas personalizadas. +$canDoSomething = $actor->can('reply', $discussion); + +// Lanza una PermissionDeniedException si un usuario no puede realizar una acción. +$actpr->assertAdmin(); + +// Comprueba si uno de los grupos del usuario tiene un permiso. +$actor->assertCan('viewForum'); +$actor->assertCan('reply', $discussion); + +// Lanza una NotAuthenticatedException si el usuario no está conectado. +$actor->assertRegistered(); + +// Lanza una PermissionDeniedException si el usuario no es un administrador. +$actorHasPermission = $actor->hasPermission(`viewForum`); +``` + +## Políticas personalizadas + +Las políticas nos permiten utilizar una lógica personalizada más allá de los simples grupos y permisos cuando se evalúa la autorización de una habilidad con un sujeto. Por ejemplo: + +- Queremos permitir a los usuarios editar los mensajes aunque no sean moderadores, pero sólo sus propios mensajes. +- Dependiendo de la configuración, podríamos permitir a los usuarios renombrar sus propias discusiones indefinidamente, durante un corto período de tiempo después de la publicación, o no en absoluto. + +Como se describe [arriba](#how-it-works), en cualquier comprobación de autorización, consultamos todas las políticas registradas para el modelo del objetivo, o cualquier clase padre del modelo del objetivo. Si no se proporciona ningún objetivo, se aplicarán todas las políticas registradas como `global`. + +Entonces, ¿cómo se "comprueba" una política? + +En primer lugar, comprobamos si la clase política tiene un método con el mismo nombre que la habilidad que se está evaluando. Si es así, lo ejecutamos con el actor y el sujeto como parámetros. Si ese método devuelve un valor no nulo, devolvemos ese resultado. En caso contrario, continuamos con el siguiente paso (no necesariamente con la siguiente política). + +A continuación, comprobamos si la clase de política tiene un método llamado `can`. Si es así, lo ejecutamos con el actor, la habilidad y el sujeto, y devolvemos el resultado. + +Si `can` no existe o devuelve null, hemos terminado con esta política, y pasamos a la siguiente. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate policies: +```bash +is_restricted) { + return $actor->hasPermission('tag'.$tag->id.'.startDiscussion') ? $this->allow() : $this->deny(); + } + } + + /** + * @param User $actor + * @param Tag $tag + * @return bool|null + */ + public function addToDiscussion(User $actor, Tag $tag) + { + return $this->startDiscussion($actor, $tag); + } +} +``` + +::: + +### Cómo funciona + +Veamos algunos ejemplos de [Flarum Tags](https://github.com/flarum/tags/blob/master/src/Access/TagPolicy). + +```php +whereIn('discussions.id', function ($query) use ($actor, $ability) { + return $query->select('discussion_id') + ->from('discussion_tag') + ->whereIn('tag_id', Tag::getIdsWhereCan($actor, 'discussion.'.$ability)); + }); + } +} +``` + +También podemos tener políticas globales, que se ejecutan cuando `$user->can()` es llamado sin una instancia del modelo de destino. De nuevo desde Tags: + +```php +settings = $settings; + } + + /** + * @param Flarum\User\User $actor + * @param string $ability + * @return bool|void + */ + public function can(User $actor, string $ability) + { + if (in_array($ability, ['viewForum', 'startDiscussion'])) { + $enoughPrimary = count(Tag::getIdsWhereCan($actor, $ability, true, false)) >= $this->settings->get('min_primary_tags'); + $enoughSecondary = count(Tag::getIdsWhereCan($actor, $ability, false, true)) >= $this->settings->get('min_secondary_tags'); + + if ($enoughPrimary && $enoughSecondary) { + return $this->allow(); + } else { + return $this->deny(); + } + } + } +} +``` + +### Cómo usar la autorización + +¿Qué ocurre cuando llamamos a `whereVisibleTo`? Esta llamada es manejada por el sistema de alcance de visibilidad del modelo general de Flarum, que ejecuta la consulta a través de una secuencia de llamadas de retorno, que se llaman "scopers". + +```php +use Flarum\Extend; +use Flarum\Tags\Tag; +use YourNamespace\Access; + +return [ + // Otros extensores + (new Extend\Policy()) + ->modelPolicy(Tag::class, Access\TagPolicy::class) + ->globalPolicy(Access\GlobalPolicy::class), + // Otros extensores +]; +``` + +## Frontend Authorization + +Comúnmente, querrás usar los resultados de la autorización en la lógica del frontend. Por ejemplo, si un usuario no tiene permiso para ver usuarios de búsqueda, no deberíamos enviar solicitudes a ese punto final. Y si un usuario no tiene permiso para editar usuarios, no deberíamos mostrar elementos del menú para ello. + +Como no podemos hacer comprobaciones de autorización en el frontend, tenemos que realizarlas en el backend, y adjuntarlas a la serialización de los datos que estamos enviando. Los permisos globales (`viewForum`, `viewUserList`) pueden incluirse en el `ForumSerializer`, pero para la autorización específica de un objeto, podemos querer incluirlos con el objeto sujeto. Por ejemplo, cuando devolvemos listas de discusiones, comprobamos si el usuario puede responder, renombrar, editar y borrar, y almacenamos esos datos en el modelo de discusión del frontend. Entonces es accesible a través de `discussion.canReply()` o `discussion.canEdit()`, pero no hay nada mágico ahí: es sólo otro atributo enviado por el serializador. + +Hay dos tipos de scopers: diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md new file mode 100644 index 000000000..90ea57107 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md @@ -0,0 +1,215 @@ +# Eventos del Backend + +A menudo, una extensión querrá reaccionar a algunos eventos que ocurren en otra parte de Flarum. Por ejemplo, podríamos querer incrementar un contador cuando se publica una nueva discusión, enviar un email de bienvenida cuando un usuario se conecta por primera vez, o añadir etiquetas a una discusión antes de guardarla en la base de datos. Estos eventos se conocen como **eventos de dominio**, y se transmiten a todo el framework a través del [sistema de eventos de Laravel](https://laravel.com/docs/6.x/events). + +Para obtener una lista completa de los eventos del backend, consulte nuestra [documentación de la API](https://api.docs.flarum.org/php/master/search.html?search=Event). Las clases de eventos del dominio están organizadas por espacio de nombres, normalmente `Flarum\TYPE\Event`. + + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate event listeners: +```bash +use Flarum\Extend; +use Flarum\Post\Event\Deleted; +use Symfony\Contracts\Translation\TranslatorInterface; + + +return [ + (new Extend\Event) + ->listen(Deleted::class, function($event) { + // haz algo aquí + }) + ->listen(Deleted::class, PostDeletedListener::class) +]; + + +class PostDeletedListener +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function handle(Deleted $event) + { + // Su lógica aquí + } +} +``` + +::: + +## Escuchar eventos + +Puedes adjuntar un oyente a un evento utilizando el [extensor] [`Event`](https://api.docs.flarum.org/php/master/flarum/extend/event)(start.md#extenders): + +```php +use Flarum\Post\Event\Deleted; +use Illuminate\Contracts\Events\Dispatcher; + + +class SomeClass +{ + /** + * @var Dispatcher + */ + protected $events; + + /** + * @param Dispatcher $events + */ + public function __construct(Dispatcher $events) + { + $this->events = $events; + } + + public function someMethod() + { + // Lógica + $this->events->dispatch( + new Deleted($somePost, $someActor) + ); + // Más lógica + } +} +``` +```php +class PostDeletedListener +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function handle(Deleted $event) + { + // Your logic here + } +} +``` + +Como se muestra arriba, se puede utilizar una clase listener en lugar de un callback. Esto le permite [inyectar dependencias](https://laravel.com/docs/6.x/container) en su clase listener a través de los parámetros del constructor. En este ejemplo resolvemos una instancia de traductor, pero podemos inyectar cualquier cosa que queramos/necesitemos. + +You can also listen to multiple events at once via an event subscriber. This is useful for grouping common functionality; for instance, if you want to update some metadata on changes to posts: + +```php +use Flarum\Extend; +use Flarum\Post\Event\Deleted; +use Flarum\Post\Event\Saving; +use Symfony\Contracts\Translation\TranslatorInterface; + + +return [ + (new Extend\Event) + ->subscribe(PostEventSubscriber::class), +]; +``` +```php +class PostEventSubscriber +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function subscribe($events) + { + $events->listen(Deleted::class, [$this, 'handleDeleted']); + $events->listen(Saving::class, [$this, 'handleSaving']); + } + + public function handleDeleted(Deleted $event) + { + // Your logic here + } + + public function handleSaving(Saving $event) + { + // Your logic here + } +} +``` + +## Dispatching de eventos + +Despachar eventos es muy sencillo. Todo lo que necesitas hacer es inyectar `Illuminate\Contracts\Events\Dispatcher` en tu clase, y luego llamar a su método `dispatch`. Por ejemplo: + +```php +use Flarum\Post\Event\Deleted; +use Illuminate\Contracts\Events\Dispatcher; + + +class SomeClass +{ + /** + * @var Dispatcher + */ + protected $events; + + /** + * @param Dispatcher $events + */ + public function __construct(Dispatcher $events) + { + $this->events = $events; + } + + public function someMethod() + { + // Logic + $this->events->dispatch( + new Deleted($somePost, $someActor) + ); + // More Logic + } +} +``` + +## Eventos personalizados + +Como desarrollador de extensiones puedes definir tus propios eventos para permitirte a ti mismo (o a otras extensiones) reaccionar a eventos en tu extensión. Los eventos son generalmente instancias de clases simples (no es necesario extender nada). Cuando definas un nuevo evento, normalmente querrás usar propiedades públicas, y quizás algunos métodos para la comodidad de los usuarios. Por ejemplo, si echamos un vistazo a `Flarum\Post\Event\Deleted`, es sólo una envoltura de algunos datos: + +```php +post = $post; + $this->actor = $actor; + } +} +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/cli.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/cli.md new file mode 100644 index 000000000..ab88b1142 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/cli.md @@ -0,0 +1,15 @@ +# Desarrolladores explicando su flujo de trabajo para el desarrollo de extensiones + +The Flarum development ecosystem is oriented around many small, modules, interacting extensions. This is a very powerful and flexible paradigm, but it also brings the maintenance cost of creating and maintaining all these extensions. + +We've created the Flarum CLI (command line interface) as a tool to help developers by automating some repetitive and menial tasks, and allow them to get into the actual work without much hassle. + +Major updates about Flarum CLI will be published [on this discussion](https://discuss.flarum.org/d/28427-flarum-cli-v10). + +See the [package's readme](https://github.com/flarum/cli#readme) for information on: + +- Instalación +- Usage +- Upgrading +- Available commands +- Some implementation details, if you're interested diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/console.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/console.md new file mode 100644 index 000000000..d989d2b02 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/console.md @@ -0,0 +1,79 @@ +# Consola + +Flarum permite a los desarrolladores de extensiones añadir comandos de consola personalizados además de los [predeterminados](../console.md) proporcionados por el núcleo de flarum. + +Todo el desarrollo de comandos de consola se realiza en el backend usando PHP. Para crear un comando de consola personalizado, necesitará crear una clase que extienda `Flarum\Console\AbstractCommand`. + +```php +use Flarum\Console\AbstractCommand; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; + +class YourCommand implements AbstractCommand { + protected function configure() + { + $this + ->setName('YOUR COMMAND NAME') + ->setDescription('YOUR COMMAND DESCRIPTION'); + } + protected function fire() + { + // Su lógica aquí + } +} + } +} +``` + +:::info [Flarum CLI](https://github.com/flarum/cli) + +:::tip Comandos Programados +```bash +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; + +return [ + // Otros extensores + (new Extend\Console())->command(CustomCommand::class) + // Otros extensores +]; +``` + +::: + +## Registro de los comandos de la consola + +To register console commands, use the `Flarum\Extend\Console` extender in your extension's `extend.php` file: + +```php +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; + +return [ + // Other extenders + (new Extend\Console())->command(CustomCommand::class) + // Other extenders +]; +``` + +## Scheduled Commands + +La [fof/console library](https://github.com/FriendsOfFlarum/console) le permite programar comandos para que se ejecuten en un intervalo regular. + + +```php +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; +use Illuminate\Console\Scheduling\Event; + +return [ + // Other extenders + (new Extend\Console())->schedule('cache:clear', function (Event $event) { + $event->everyMinute(); + }, ['Arg1', '--option1', '--option2']), + // Other extenders +]; +``` + +In the callback provided as the second argument, you can call methods on the [$event object](https://laravel.com/api/8.x/Illuminate/Console/Scheduling/Event.html) to schedule on a variety of frequencies (or apply other options, such as only running on one server). See the [Laravel documentation](https://laravel.com/docs/8.x/scheduling#scheduling-artisan-commands) for more information. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/data.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/data.md new file mode 100644 index 000000000..88de40415 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/data.md @@ -0,0 +1,562 @@ +# Trabajar con datos + +Los datos son la base de cualquier foro, así que vas a tener que jugar bien con ellos si quieres que tu extensión haga algo útil. Este documento repasa cómo fluyen los datos en Flarum, desde la base de datos hasta el JSON-API y el frontend, y todo el camino de vuelta. + +Flarum utiliza el componente de base de datos de [Laravel](https://laravel.com/docs/database). Debes familiarizarte con él antes de continuar, ya que se asume como conocimiento previo en la siguiente documentación. + +## Ciclo de vida de las solicitudes de la API + +Antes de entrar en detalles sobre cómo ampliar la API de datos de Flarum, vale la pena pensar en el ciclo de vida de una solicitud de datos típica: + +1. Se envía una solicitud HTTP a la API de Flarum. Normalmente, esto vendrá del frontend de Flarum, pero los programas externos también pueden interactuar con la API. La API de Flarum sigue en su mayoría la especificación [JSON:API](https://jsonapi.org/), por lo que, en consecuencia, las solicitudes deben seguir [dicha especificación](https://jsonapi.org/format/#fetching). +2. La solicitud se ejecuta a través de [middleware](middleware.md), y se dirige al controlador adecuado. Puedes aprender más sobre los controladores en su conjunto en nuestra [documentación sobre rutas y contenido](routes.md). Asumiendo que la petición es a la API (que es el caso de esta sección), el controlador que maneja la petición será una subclase de `Flarum\Api\AbstractSerializeController`. +3. Cualquier modificación realizada por las extensiones del controlador a través del extensor [`ApiController`] (#extending-api-controllers) se aplica. Esto podría suponer el cambio de sort, añadir includes, cambiar el serializador, etc. +4. Se llama al método `$this->data()` del controlador, obteniendo algunos datos en bruto que deben ser devueltos al cliente. Típicamente, estos datos tomarán la forma de una colección o instancia del modelo de Laravel Eloquent, que ha sido recuperada de la base de datos. Dicho esto, los datos pueden ser cualquier cosa siempre que el serializador del controlador pueda procesarlos. Cada controlador es responsable de implementar su propio método `data`. Ten en cuenta que para las peticiones `PATCH`, `POST` y `DELETE`, `data` realizará la operación en cuestión, y devolverá la instancia del modelo modificado. +5. Esos datos se ejecutan a través de cualquier callback de preserialización que las extensiones registren a través del extensor [`ApiController`](#extending-api-controllers). +6. Los datos se pasan a través de un [serializador](#serializers), que los convierte del formato de base de datos del backend al formato JSON:API esperado por el frontend. También adjunta cualquier objeto relacionado, que se ejecuta a través de sus propios serializadores. Como explicaremos más adelante, las extensiones pueden [añadir / anular relaciones y atributos](#attributes-and-relationships) en el nivel de serialización. +7. Los datos serializados se devuelven como una respuesta JSON al frontend. +8. Si la solicitud se originó a través de la `Store` del frontend de Flarum, los datos devueltos (incluyendo cualquier objeto relacionado) serán almacenados como [modelos del frontend](#frontend-models) en el almacén del frontend. + +## Migraciones + +Si queremos utilizar un modelo personalizado, o añadir atributos a uno existente, tendremos que modificar la base de datos para añadir tablas / columnas. Esto lo hacemos a través de las migraciones. + +Las migraciones son como un control de versiones para su base de datos, permitiéndole modificar fácilmente el esquema de la base de datos de Flarum de forma segura. Las migraciones de Flarum son muy similares a las de [Laravel](https://laravel.com/docs/migrations), aunque hay algunas diferencias. + +Las migraciones viven dentro de una carpeta convenientemente llamada `migrations` en el directorio de su extensión. Las migraciones deben ser nombradas en el formato `YYY_MM_DD_HHMMSS_snake_case_description` para que sean listadas y ejecutadas en orden de creación. + +### Estructura de la migración + +En Flarum, los archivos de migración deben **devolver un array** con dos funciones: `up` y `down`. La función `up` se utiliza para añadir nuevas tablas, columnas o índices a tu base de datos, mientras que la función `down` debe revertir estas operaciones. Estas funciones reciben una instancia del [Laravel schema builder](https://laravel.com/docs/6.x/migrations#creating-tables) que puedes usar para alterar el esquema de la base de datos: + +```php + function (Builder $schema) { + // up migration + }, + 'down' => function (Builder $schema) { + // down migration + } +]; +``` + +Para tareas comunes como la creación de una tabla, o la adición de columnas a una tabla existente, Flarum proporciona algunos ayudantes que construyen esta matriz para usted, y se encargan de escribir la lógica de migración `down` mientras están en ello. Están disponibles como métodos estáticos en la clase `Flarum\Database\Migration`. + +### Ciclo de vida de las migraciones + +Las migraciones se aplican cuando la extensión se habilita por primera vez o cuando está habilitada y hay algunas migraciones pendientes. Las migraciones ejecutadas se registran en la base de datos, y cuando se encuentran algunas en la carpeta de migraciones de una extensión que no están registradas como completadas todavía, se ejecutarán. + +Las migraciones también pueden aplicarse manualmente con `php flarum migrate`, que también es necesario para actualizar las migraciones de una extensión ya habilitada. Para deshacer los cambios aplicados por las migraciones, es necesario hacer clic en "Desinstalar" junto a una extensión en la interfaz de administración, o utilizar el comando `php flarum migrate:reset`. No se puede romper nada ejecutando `php flarum migrate` de nuevo si ya has migrado - las migraciones ejecutadas no se ejecutarán de nuevo. + +Actualmente no hay ganchos a nivel de compositor para gestionar las migraciones en absoluto (es decir, actualizar una extensión con `composer update` no ejecutará sus migraciones pendientes). + +### Creación de tablas + +Para crear una tabla, utilice el ayudante `Migration::createTable`. El ayudante `createTable` acepta dos argumentos. El primero es el nombre de la tabla, mientras que el segundo es un `Closure` que recibe un objeto `Blueprint` que puede ser utilizado para definir la nueva tabla: + +```php +use Flarum\Database\Migration; +use Illuminate\Database\Schema\Blueprint; + +return Migration::createTable('users', function (Blueprint $table) { + $table->increments('id'); +}); +``` + +Al crear la tabla, puede utilizar cualquiera de los [métodos de columna](https://laravel.com/docs/6.x/migrations#creating-columns) del constructor de esquemas para definir las columnas de la tabla. + +### Renombrar Tablas + +Para renombrar una tabla de la base de datos existente, utilice el ayudante `Migration::renameTable`: + +```php +return Migration::renameTable($from, $to); +``` + +### Crear/eliminar columnas + +Para añadir columnas a una tabla existente, utilice el ayudante `Migration::addColumns`. El ayudante `addColumns` acepta dos argumentos. El primero es el nombre de la tabla. El segundo es un array de definiciones de columnas, cuya clave es el nombre de la columna. El valor de cada elemento es un array con las definiciones de las columnas, tal y como lo entiende el método `Illuminate\Database\Schema\Blueprint::addColumn()` de Laravel. El primer valor es el tipo de columna, y cualquier otro valor clave se pasa a través de `addColumn`. + +```php +return Migration::addColumns('users', [ + 'email' => ['string', 'nullable' => true], + 'discussion_count' => ['integer', 'unsigned' => true] +]); +``` + +Para eliminar columnas de una tabla existente, utilice el ayudante `Migration::dropColumns`, que acepta los mismos argumentos que el ayudante `addColumns`. Al igual que cuando se eliminan tablas, se deben especificar las definiciones completas de las columnas para que la migración se pueda revertir limpiamente. + +### Renombrar columnas + +Para cambiar el nombre de las columnas, utilice el ayudante `Migration::renameColumns`. El ayudante `renameColumns` acepta dos argumentos. El primero es el nombre de la tabla, mientras que el segundo es un array de nombres de columnas a renombrar: + +```php +return Migration::renameColumns('users', ['from' => 'to']); +``` + +### Migraciones de Datos (Avanzado) + +Una migración no tiene por qué cambiar la estructura de la base de datos: puedes utilizar una migración para insertar, actualizar o eliminar filas en una tabla. Por ejemplo, puedes utilizar las migraciones para asignar [permisos personalizados](permissions.md) a otros grupos que no sean el de Administrador, o proporcionar algunos datos iniciales para un modelo personalizado de Eloquent. Dado que tienes acceso al [Eloquent Schema Builder](https://laravel.com/docs/6.x/migrations#creating-tables), todo es posible (aunque, por supuesto, debes ser extremadamente cauteloso y probar tu extensión extensamente). + +Las migraciones de datos son la forma recomendada de especificar la configuración y los permisos por defecto. + +## Modelos del backend + +Con todas tus nuevas tablas y columnas de la base de datos, vas a querer una forma de acceder a los datos tanto en el backend como en el frontend. En el backend es bastante sencillo - sólo necesitas estar familiarizado con [Eloquent](https://laravel.com/docs/6.x/eloquent). + +### Añadir nuevos modelos + +Si has añadido una nueva tabla, tendrás que crear un nuevo modelo para ella. En lugar de extender la clase `Model` de Eloquent directamente, deberías extender `Flarum\Database\AbstractModel` que proporciona un poco de funcionalidad extra para permitir que tus modelos sean extendidos por otras extensiones. + + + +### Relaciones + +También puedes añadir [relaciones](https://laravel.com/docs/6.x/eloquent-relationships) a los modelos existentes utilizando los métodos `hasOne`, `belongsTo`, `hasMany`, `belongsToMany` y `relationship` del extensor `Model`. El primer argumento es el nombre de la relación; el resto de los argumentos se pasan al método equivalente en el modelo, por lo que se puede especificar el nombre del modelo relacionado y, opcionalmente, anular los nombres de las tablas y las claves: + +```php + new Extend\Model(User::class) + ->hasOne('phone', 'App\Phone', 'foreign_key', 'local_key') + ->belongsTo('country', 'App\Country', 'foreign_key', 'other_key') + ->hasMany('comment', 'App\Comment', 'foreign_key', 'local_key') + ->belongsToMany('role', 'App\Role', 'role_user', 'user_id', 'role_id') +``` + +Estos 4 métodos deberían cubrir la mayoría de las relaciones, pero a veces se necesita una personalización más fina (por ejemplo, `morphMany`, `morphToMany` y `morphedByMany`). Cualquier relación válida de Eloquent es soportada por el método `relationship`: + +```php + new Extend\Model(User::class) + ->relationship('mobile', 'App\Phone', function ($user) { + // Devuelve aquí cualquier relación Eloquent. + return $user->belongsToMany(Discussion::class, 'recipients') + ->withTimestamps() + ->wherePivot('removed_at', null); + }) +``` + +## Serializadores + +El siguiente paso es exponer tus nuevos datos en el JSON:API de Flarum para que puedan ser consumidos por el frontend. Debes familiarizarte con la [especificación JSON:API](https://jsonapi.org/format/). La capa JSON:API de Flarum se alimenta de la biblioteca [tobscure/json-api](https://github.com/tobscure/json-api). + +Los recursos JSON:API son definidos por **serializadores**. Para definir un nuevo tipo de recurso, crea una nueva clase de serializador que extienda `FlarumApi\Serializer\AbstractSerializer`. Debe especificar un recurso `$type` e implementar el método `getDefaultAttributes` que acepta la instancia del modelo como único argumento: + +```php +use Flarum\Api\Serializer\AbstractSerializer; +use Flarum\Api\Serializer\UserSerializer; + +class DiscussionSerializer extends AbstractSerializer +{ + protected $type = 'discussions'; + + protected function getDefaultAttributes($discussion) + { + return [ + 'title' => $discussion->title, + ]; + } +} +``` + +### Atributos y relaciones + +También puedes especificar relaciones para tu recurso. Simplemente crea un nuevo método con el mismo nombre que la relación en tu modelo, y devuelve una llamada a `hasOne` o `hasMany` dependiendo de la naturaleza de la relación. Debes pasar la instancia del modelo y el nombre del serializador a utilizar para los recursos relacionados. + +```php + protected function user($discussion) + { + return $this->hasOne($discussion, UserSerializer::class); + } +``` + +Para añadir **atributos** y **relaciones** a un tipo de recurso existente, utilice el extensor `ApiSerializer`: + +```php +use Flarum\Api\Serializer\UserSerializer; + +return [ + (new Extend\ApiSerializer(UserSerializer::class)) + // Un atributo a la vez + ->attribute('firstName', function ($serializer, $user, $attributes) { + return $user->first_name + }) + // Múltiples modificaciones a la vez, lógica más compleja + ->mutate(function($serializer, $user, $attributes) { + $attributes['someAttribute'] = $user->someAttribute; + if ($serializer->getActor()->can('administrate')) { + $attributes['someDate'] = $serializer->formatDate($user->some_date); + } + + return $attributes; + }) + // Relaciones de la API + ->hasOne('phone', PhoneSerializer::class) + ->hasMany('comments', CommentSerializer::class), +] +``` + +## API Endpoints + +Una vez que hayas definido tus recursos en los serializadores, necesitarás exponerlos como puntos finales de la API añadiendo rutas y controladores. + +Siguiendo las convenciones de JSON-API, puedes añadir cinco rutas estándar para tu tipo de recurso utilizando el extensor `Routes`: + +```php + (new Extend\Routes('api')) + ->get('/tags', 'tags.index', ListTagsController::class) + ->get('/tags/{id}', 'tags.show', ShowTagController::class) + ->post('/tags', 'tags.create', CreateTagController::class) + ->patch('/tags/{id}', 'tags.update', UpdateTagController::class) + ->delete('/tags/{id}', 'tags.delete', DeleteTagController::class) +``` + +El espacio de nombres `Flarum\Api\Controller` contiene una serie de clases abstractas de controladores que puedes extender para implementar fácilmente tus recursos JSON-API. + +### Listado de recursos + +Para el controlador que enumera su recurso, extienda la clase `FlarumApi\Controller\AbstractListController`. Como mínimo, necesitas especificar el `$serializer` que quieres usar para serializar tus modelos, e implementar un método `data` para devolver una colección de modelos. El método `data` acepta el objeto `Request` y el `Document` tobscure/json-api. + +```php +use Flarum\Api\Controller\AbstractListController; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ListTagsController extends AbstractListController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + return Tag::all(); + } +} +``` + +### Mostrar un recurso + +Para el controlador que muestra un solo recurso, extienda la clase `Flarum\Api\Controller\AbstractShowController`. Al igual que para el controlador de la lista, es necesario especificar el `$serializer` que desea utilizar para serializar sus modelos, e implementar un método `data` para devolver un solo modelo: + +```php +use Flarum\Api\Controller\AbstractShowController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ShowTagController extends AbstractShowController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + return Tag::findOrFail($id); + } +} +``` + +### Creación de un recurso + +Para el controlador que crea un recurso, extienda la clase `Flarum\Api\Controller\AbstractCreateController`. Esto es lo mismo que el controlador de mostrar, excepto que el código de estado de la respuesta se establecerá automáticamente a `201 Created`. Puede acceder al cuerpo del documento JSON:API entrante a través de `$request->getParsedBody()`: + +```php +use Flarum\Api\Controller\AbstractCreateController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class CreateTagController extends AbstractCreateController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $attributes = Arr::get($request->getParsedBody(), 'data.attributes'); + + return Tag::create([ + 'name' => Arr::get($attributes, 'name') + ]); + } +} +``` + +### Actualización de un recurso + +Para el controlador que actualiza un recurso, extienda la clase `Flarum\Api\Controller\AbstractShowController`. Al igual que para el controlador de creación, puedes acceder al cuerpo del documento JSON:API entrante a través de `$request->getParsedBody()`. + +### Borrar un recurso + +Para el controlador que borra un recurso, extienda la clase `Flarum\Api\Controller\AbstractDeleteController`. Sólo necesitas implementar un método `delete` que ejecute el borrado. El controlador devolverá automáticamente una respuesta vacía `204 No Content`. + +```php +use Flarum\Api\Controller\AbstractDeleteController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; + +class DeleteTagController extends AbstractDeleteController +{ + protected function delete(Request $request) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + Tag::findOrFail($id)->delete(); + } +} +``` + +### ncluir Relaciones + +Para incluir las relaciones al **enumerar**, **mostrar** o **crear** su recurso, especifíquelas en las propiedades `$include` y `$optionalInclude` de su controlador: + +```php + // Las relaciones que se incluyen por defecto. + public $include = ['user']; + + // Otras relaciones que están disponibles para ser incluidas. + public $optionalInclude = ['discussions']; +``` + +A continuación, puede obtener una lista de relaciones incluidas utilizando el método `extractInclude`. Esto se puede utilizar para cargar con avidez las relaciones en sus modelos antes de que se serialicen: + +```php +$relations = $this->extractInclude($request); + +return Tag::all()->load($relations); +``` + +### Paginación + +Puede permitir que el número de recursos que se **liste** sea personalizado especificando las propiedades `limit` y `maxLimit` en su controlador: + +```php + // El número de registros incluidos por defecto. + public $limit = 20; + + // El número máximo de registros que se pueden solicitar. + public $maxLimit = 50; +``` + +A continuación, puede extraer la información de paginación de la solicitud utilizando los métodos `extractLimit` y `extractOffset`: + +```php +$limit = $this->extractLimit($request); +$offset = $this->extractOffset($request); + +return Tag::skip($offset)->take($limit); +``` + +Para añadir enlaces de paginación al documento JSON:API, utilice el método [`Document::addPaginationLinks`](https://github.com/tobscure/json-api#meta--links). + +### Clasificación + +Puede permitir que se personalice el orden de clasificación de los recursos que se **listen** especificando las propiedades `sort` y `sortField` en su controlador: + +```php + // El campo de clasificación por defecto y el orden a utilizar. + public $sort = ['name' => 'asc']; + + // Los campos que están disponibles para ser ordenados. + public $sortFields = ['firstName', 'lastName']; +``` + +A continuación, puede extraer la información de ordenación de la solicitud utilizando el método `extractSort`. Esto devolverá un array de criterios de ordenación que puedes aplicar a tu consulta: + +```php +$sort = $this->extractSort($request); +$query = Tag::query(); + +foreach ($sort as $field => $order) { + $query->orderBy(snake_case($field), $order); +} + +return $query->get(); +``` + +### Extensión de los controladores de la API + +También es posible personalizar todas estas opciones en controladores de API _existentes_ mediante el extensor `ApiController`. + +```php +use Flarum\Api\Event\WillGetData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->setSerializer(MyDiscussionSerializer::class) + ->addInclude('user') + ->addOptionalInclude('posts') + ->setLimit(20) + ->setMaxLimit(50) + ->setSort(['name' => 'asc']) + ->addSortField('firstName') + ->prepareDataQuery(function ($controller) { + // Añade aquí la lógica personalizada para modificar el controlador + // antes de que se ejecuten las consultas de datos. + }) +] +``` + +El extensor `ApiController` también puede utilizarse para ajustar los datos antes de la serialización + +```php +use Flarum\Api\Event\WillSerializeData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->prepareDataForSerialization(function ($controller, $data, $request, $document) { + $data->load('myCustomRelation'); + }), +] +``` + +## Modelos Frontend + +Ahora que has expuesto tus datos en el JSON:API de Flarum, es finalmente el momento de darles vida y consumirlos en el frontend. + +### Obtención de datos + +El frontend de Flarum contiene un `store` de datos local que proporciona una interfaz para interactuar con el JSON:API. Puedes recuperar recursos de la API usando el método `find`, que siempre devuelve una promesa: + + +```js +// GET /api/discussions?sort=createdAt +app.store.find('discussions', {sort: 'createdAt'}).then(console.log); + +// GET /api/discussions/123 +app.store.find('discussions', 123).then(console.log); +``` + +Una vez cargados los recursos, se guardarán en la caché del almacén para que puedas acceder a ellos de nuevo sin tener que recurrir a la API utilizando los métodos `all` y `getById`: + +```js +const discussions = app.store.all('discussions'); +const discussion = app.store.getById('discussions', 123); +``` + +El almacén envuelve los datos brutos de los recursos de la API en objetos modelo que facilitan el trabajo. Se puede acceder a los atributos y relaciones a través de métodos de instancia predefinidos: + +```js +const id = discussion.id(); +const title = discussion.title(); +const posts = discussion.posts(); // array de modelos Post +``` + +Puede obtener más información sobre el almacén en nuestra [documentación de la API] (https://api.docs.flarum.org/js/master/class/src/common/store.js~store). + +### Añadir nuevos modelos + +Si has añadido un nuevo tipo de recurso, tendrás que definir un nuevo modelo para él. Los modelos deben extender la clase `Model` y redefinir los atributos y relaciones del recurso: + + +```js +import Model from 'flarum/Model'; + +export default class Tag extends Model { + title = Model.attribute('title'); + createdAt = Model.attribute('createdAt', Model.transformDate); + parent = Model.hasOne('parent'); + discussions = Model.hasMany('discussions'); +} +``` + +A continuación, debe registrar su nuevo modelo en el almacén: + +```js +app.store.models.tags = Tag; +``` + + + +### Extender los modelos + +Para añadir atributos y relaciones a los modelos existentes, modifique el prototipo de la clase del modelo: + +```js +Discussion.prototype.user = Model.hasOne('user'); +Discussion.prototype.posts = Model.hasMany('posts'); +Discussion.prototype.slug = Model.attribute('slug'); +``` + + + +### Ahorro de recursos + +Para enviar datos a través de la API, llame al método `save` en una instancia del modelo. Este método devuelve una Promise que se resuelve con la misma instancia del modelo: + +```js +discussion.save({ title: 'Hello, world!' }).then(console.log); +``` + +También puede guardar las relaciones pasándolas en una clave `relationships`. Para las relaciones has-one, pasa una única instancia del modelo. Para las relaciones has-muchos, pasa una matriz de instancias del modelo. + +```js +user.save({ + relationships: { + groups: [ + store.getById('groups', 1), + store.getById('groups', 2) + ] + } +}) +``` + +### Creación de nuevos recursos + +Para crear un nuevo recurso, cree una nueva instancia del modelo para el tipo de recurso utilizando el método `createRecord` de la tienda, y luego `save`: + +```js +const discussion = app.store.createRecord('discussions'); + +discussion.save({ title: 'Hello, world!' }).then(console.log); +``` + +### Borrar recursos + +Para eliminar un recurso, llame al método `delete` en una instancia del modelo. Este método devuelve una Promise: + +```js +discussion.delete().then(done); +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md new file mode 100644 index 000000000..dc5fe6845 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md @@ -0,0 +1,40 @@ +# Distribución + +Has escrito una gran extensión y ahora quieres que todo el mundo pueda usarla. Este documento te llevará a través del proceso de distribución, desde la creación de un repositorio Git para tu extensión, hasta su publicación en Packagist. + +## Configurar Git + +Lo primero que tienes que hacer es configurar un sistema de control de versiones (VCS). El VCS más popular es [Git](https://git-scm.com/). En esta guía usaremos Git, así que asegúrate de tenerlo [instalado](https://git-scm.com/downloads) antes de continuar. Si no tienes muchos conocimientos sobre Git, puedes consultar [estos recursos de aprendizaje](https://try.github.io/). + +Después de haber instalado Git, necesitarás inicializar tu repositorio. Puedes usar `git init` en la línea de comandos si te sientes cómodo, o usar una herramienta GUI como [SourceTree](https://www.sourcetreeapp.com/) o [GitKraken](https://www.gitkraken.com/). + +A continuación, necesitarás una cuenta en un servidor de alojamiento de Git, siendo los más populares [GitHub](https://github.com) y [GitLab](https://gitlab.com). Estos te indicarán cómo conectar tu repositorio local con el repositorio "remoto" en línea. + +## Etiquetar una versión + +Como vas a publicar esta extensión, querrás asegurarte de que la información está actualizada. Tómese un minuto para revisar `composer.json` y asegurarse de que el nombre del paquete, la descripción y la información de la extensión Flarum son correctos. Se recomienda tener un archivo `README.md` en su repositorio para explicar qué es la extensión, así que cree uno si aún no lo ha hecho. + +Cuando esté listo para publicar, envíe los archivos de su extensión al repositorio y etiquete su primera versión: + +```bash +git tag v0.1.0 +git push && git push --tags +``` + +## Publicar en Packagist + +Los paquetes de Composer se publican en un repositorio de Composer, normalmente [Packagist](https://packagist.org/). Necesitarás una cuenta para proceder. + +Si esta es la primera versión que publicas de tu extensión, tendrás que [enviar tu paquete](https://packagist.org/packages/submit) utilizando la URL de su repositorio público. Si tu extensión se encuentra en GitHub, esta URL será algo así como `https://github.com/AUTHOR/NAME.git`. + +### Future Releases + +You can set up Packagist to [auto-update packages](https://packagist.org/about#how-to-update-packages). Then for future releases, all you will need to do with Git is commit, tag, and push it to the remote server. + +## Promover su extensión + +Lo más probable es que quieras crear una discusión en la Comunidad Flarum en la [etiqueta de extensiones](https://discuss.flarum.org/t/extensions). Otras personas pueden instalar su extensión usando el siguiente comando: + +```bash +composer require vendor/package +``` \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md new file mode 100644 index 000000000..5e2cb1d54 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md @@ -0,0 +1,122 @@ +# Extending Extensions + +Flarum extensions aren't just for adding features to core: extensions can extend other extensions! + +:::tip + +To learn how to make your extension extensible, see the [relevant documentation](extensibility.md) + +::: + +## Dependencies + +If your extension relies on another extension, you'll want to ensure that: + +- The other extension is installed and enabled before yours can be. +- The other extension can't be disabled while yours is enabled. +- The other extension is booted before your extension. + +Flarum makes this very easy: just add the other extension to your extension's `composer.json`'s `require` section. + +For example, if you were building a new theme for the Flarum Tags extension, your `composer.json` would look like this: + +```json +{ + // ... + "require": { + "flarum/core": "^0.1.0-beta.15", // Since all extensions need to require core. + "flarum/tags": "^0.1.0-beta.15" // This tells Flarum to treat tags as a dependency of your extension. + }, + // ... +} +``` + +## Optional Dependencies + +Sometimes, extension A might want to extend extension B only if extension B is enabled. In this case, we call B an "Optional Dependency" of A. For instance, a drafts extension might want to add support for saving private discussion drafts, but only if the private discussion extension is enabled. + +The first step here is detecting whether extension B is enabled. In the frontend, this is easy: if extension B does anything in the frontend, its extension ID will appear as a key in the `flarum.extensions` global object. Por ejemplo: + +```js +if ('some-extension-id' in flarum.extensions) { + // do something +} +``` + +In the backend, you'll need to inject an instance of `Flarum\Extension\ExtensionManager`, and use its `isEnabled()` method. Por ejemplo: + +```php +extensions = $extensions; + } + + public function someMethod() + { + if ($this->extensions->isEnabled('some-extension-id')) { + // do something. + } + } +} +``` + +Generally, if your extension has optional dependencies, you'll want it to be booted after said optional dependencies. You can also do this by specifying composer package names (NOT flarum extension IDs) in an array for the `extra.flarum-extension.optional-dependencies` key of your composer.json. + +Por ejemplo: + +```json +{ + // ... + "extra": { + "flarum-extension": { + "optional-dependencies": [ + "flarum/tags" + ] + } + }, + // ... +} +``` + +## Importing from Extensions + +In the backend, you can import the classes you need via regular PHP `use` statements: + +```php + { + // Your Extension Code Here +}) + +export { + // Put all the stuff you want to export here. +} +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md new file mode 100644 index 000000000..ef202b2c7 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md @@ -0,0 +1,129 @@ +# Filesystem + +Flarum core integrates with the filesystem to store and serve assets (like compiled JS/CSS or upload logos/favicons) and avatars. + +Extensions can use Flarum's provided utils for their own filesystem interaction and file storage needs. This system is based around [Laravel's filesystem tools](https://laravel.com/docs/8.x/filesystem), which are in turn based on the [Flysystem library](https://github.com/thephpleague/flysystem). + +## Disks + +Filesystem **disks** represent storage locations, and are backed by storage drivers, which we'll cover later. Flarum core has 2 disks: `flarum-assets` and `flarum-avatars`. + +### Using existing disks + +To access a disk, you'll need to retrieve it from the [Filesystem Factory](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Factory.html). To do so, you should inject the factory contract in your class, and access the disks you need. + +Let's take a look at core's [`DeleteLogoController`](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Controller/DeleteLogoController.php#L19-L58) for an example: + +```php +settings = $settings; + $this->uploadDir = $filesystemFactory->disk('flarum-assets'); + } + + /** + * {@inheritdoc} + */ + protected function delete(ServerRequestInterface $request) + { + RequestUtil::getActor($request)->assertAdmin(); + + $path = $this->settings->get('logo_path'); + + $this->settings->set('logo_path', null); + + if ($this->uploadDir->exists($path)) { + $this->uploadDir->delete($path); + } + + return new EmptyResponse(204); + } +} +``` + +The object returned by `$filesystemFactory->disk(DISK_NAME)` implements the [Illuminate\Contracts\Filesystem\Cloud](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Cloud.html) interface, and can be used to create/get/move/delete files, and to get the URL to a resource. + +### Declaring new disks + +Some extensions will want to group their resources / uploads onto a custom disk as opposed to using `flarum-assets` or `flarum-avatars`. + +This can be done via the `Filesystem` extender: + +```php +use Flarum\Extend; + +return [ + (new Extend\Filesystem) + ->disk('flarum-uploads', function (Paths $paths, UrlGenerator $url) { + return [ + 'root' => "$paths->public/assets/uploads", + 'url' => $url->to('forum')->path('assets/uploads') + ]; + }); +``` + +Since all disks use the local filesystem by default, you'll need to provide a base path and base URL for the local filesystem. + +The config array can contain other entries supported by [Laravel disk config arrays](https://laravel.com/docs/8.x/filesystem#configuration). The `driver` key should not be provided, and will be ignored. + +## Storage drivers + +Flarum selects the active driver for each disk by checking the `disk_driver.DISK_NAME` key in the [settings repository](settings.md) and [config.php file](../config.md). If no driver is configured, or the configured driver is unavailable, Flarum will default to the `local` driver. + +You can define new storage drivers by implementing the [`Flarum\Filesystem\DriverInterface` interface](https://github.com/flarum/framework/blob/main/framework/core/src/Filesystem/DriverInterface.php#L16), and registering it via the `Filesystem` extender: + +```php +use Flarum\Extend; + +return [ + (new Extend\Filesystem) + ->driver('aws-with-cdn', AwsWithCdnDriver::class); +``` + +Filesystem storage drivers are a very powerful tool that allows you to completely customize file storage locations, attach arbitrary CDNs, and otherwise extend the filesystem / cloud storage integration layer. + +:::danger + +Some drivers might try to index their filesystem every time the driver is instantiated, even if only the `url` method is needed. This can have serious performance implications. In most cases, you'll want to ensure that your driver's `url` method does not ping the remote filesystem. Similarly, the remote filesystem should usually not be accessed until operations are actually executed. + +::: + +## GUI and Admin Configuration + +Flarum does not currently provide a GUI for selecting drivers for disks, or for entering settings for drivers. This might be added in the future. For now, extensions are responsible for providing a GUI for their disks and drivers. + +As noted [above](#storage-drivers), if your extension provides a GUI for selecting drivers for a disk, it should modify the `disk_driver.DISK_NAME` key in settings. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md new file mode 100644 index 000000000..5020b6774 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md @@ -0,0 +1,42 @@ +# Formatting + +Flarum utiliza la potente biblioteca [s9e TextFormatter](https://github.com/s9e/TextFormatter) para dar formato a los mensajes desde el marcado simple hasta el HTML. Deberías familiarizarte con [cómo funciona TextFormatter](https://s9etextformatter.readthedocs.io/Getting_started/How_it_works/) antes de intentar extenderlo. + +En Flarum, el contenido de las entradas se formatea con una configuración mínima de TextFormatter por defecto. Las extensiones **Markdown** y **BBCode** incluidas simplemente habilitan los respectivos plugins en esta configuración de TextFormatter. + +## Configuración + +Puedes configurar la instancia del `Configurador` de TextFormatter, así como ejecutar una lógica personalizada durante el análisis sintáctico y la renderización, utilizando el extensor `Formatter`: + +```php +use Flarum\Extend; +use Psr\Http\Message\ServerRequestInterface as Request; +use s9e\TextFormatter\Configurator; +use s9e\TextFormatter\Parser; +use s9e\TextFormatter\Renderer; + +return [ + (new Extend\Formatter) + // Añadir la configuración del formateador de texto personalizado + ->configure(function (Configurator $config) { + $config->BBCodes->addFromRepository('B'); + }) + // Modificar el texto en bruto antes de analizarlo. + // Esta llamada de retorno debe devolver el texto modificado. + ->parse(function (Parser $parser, $context, $text) { + // lógica personalizada aquí + return $newText; + }) + // Modificar el XML a renderizar antes de renderizar. + // Esta llamada de retorno debe devolver el nuevo XML. + // Por ejemplo, en la extensión de menciones, esto se utiliza para + // proporcionar el nombre de usuario y el nombre para mostrar del usuario que está siendo mencionado. + // Asegúrese de que el último argumento $request sea nulo (u omitido por completo). + ->render(function (Renderer $renderer, $context, $xml, Request $request = null) { + // lógica personalizada aquí + return $newXml; + }) +]; +``` + +Con una buena comprensión de TextFormatter, esto le permitirá lograr cualquier cosa, desde simples adiciones de etiquetas BBCode hasta tareas de formato más complejas como la extensión **Mentions** de Flarum. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/forms.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/forms.md new file mode 100644 index 000000000..f92cabe23 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/forms.md @@ -0,0 +1,108 @@ +# Formularios y peticiones + +En este artículo, repasaremos algunas herramientas de frontend que tenemos a nuestra disposición para construir y gestionar formularios, así como la forma de enviar peticiones HTTP a través de Flarum. + +## Componentes de los formularios + +Como en cualquier sitio interactivo, es probable que quiera incluir formularios en algunas páginas y modales. Flarum proporciona algunos componentes para facilitar la construcción (¡y el estilo!) de estos formularios. Por favor, consulte la documentación de la API vinculada para cada uno de ellos para obtener más información sobre sus atributos aceptados. + +- El componente [`flarum/components/FieldSet`](https://api.docs.flarum.org/js/master/class/src/common/components/fieldset.js~fieldset) envuelve a sus hijos en una etiqueta HTML fieldset, con una leyenda. +- El componente [`flarum/components/Select`](https://api.docs.flarum.org/js/master/class/src/common/components/select.js~select) es una entrada de selección estilizada. +- Los componentes [`flarum/components/Switch`](https://api.docs.flarum.org/js/master/class/src/common/components/switch.js~switch) y [`flarum/components/Checkbox`](https://api.docs.flarum.org/js/master/class/src/common/components/checkbox.js~checkbox) son componentes de entrada de casilla de verificación estilizados. Su attr `loading` puede establecerse en `true` para mostrar un indicador de carga. +- El componente [`flarum/components/Button`](https://api.docs.flarum.org/js/master/class/src/common/components/button.js~button) es un botón estilizado, y se utiliza frecuentemente en Flarum. + +Normalmente querrás asignar la lógica para reaccionar a los cambios de entrada a través de los attrs `on*` de Mithril, no de los listeners externos (como es común con jQuery o JS simple). Por ejemplo: + +```jsx +import Component from 'flarum/Component'; +import FieldSet from 'flarum/components/FieldSet'; +import Button from 'flarum/components/Button'; +import Switch from 'flarum/components/Switch'; + + +class FormComponent extends Component { + oninit(vnode) { + this.textInput = ""; + this.booleanInput = false; + } + + view() { + return ( +
+
+ this.textInput = e.target.value}> + + this.booleanInput = val}> + +
+ +
+ ) + } + + onsubmit() { + // Lógica de manejo de formularios aquí + } +} +``` + +¡No olvides utilizar [traducciones](translate.md)! + + +## Streams, bidi, y withAttr + +Flarum proporciona [Mithril's Stream](https://mithril.js.org/stream.html) como `flarum/util/Stream`. Esta es una estructura de datos reactiva muy poderosa, pero es más comúnmente usada en Flarum como una envoltura para datos de formularios. Su uso básico es: + +```js +import Stream from 'flarum/utils/Stream'; + + +const value = Stream("hello!"); +value() === "hello!"; // verdadero +value("world!"); +value() === "world!"; // verdadero +``` + +En los formularios de Flarum, los flujos se utilizan frecuentemente junto con el attr bidi. Bidi significa unión bidireccional, y es un patrón común en los frameworks de frontend. Flarum parchea Mithril con la librería [`m.attrs.bidi`](https://github.com/tobyzerner/m.attrs. Esto abstrae el procesamiento de la entrada en Mithril. Por ejemplo: + +```jsx +import Stream from 'flarum/utils/Stream'; + +const value = Stream(); + +// Sin bidi + value(e.target.value)}> + +// Con bidi + +``` + +También puedes utilizar la utilidad `flarum/utils/withAttr` para simplificar el procesamiento de formularios. `withAttr` llama a un callable, proporcionando como argumento algún attr del elemento DOM ligado al componente en cuestión: + +```jsx +import Stream from 'flarum/utils/Stream'; +import withAttr from 'flarum/utils/withAttr'; + +const value = Stream(); + +// With a stream + + +// With any callable + { + // Some custom logic here +})}> +``` + +## Haciendo peticiones + +En nuestra documentación de [modelos y datos](data.md), aprendiste a trabajar con modelos, y a guardar la creación, los cambios y la eliminación de modelos en la base de datos a través de la utilidad Store, que no es más que una envoltura del sistema de peticiones de Flarum, que a su vez no es más que una envoltura del sistema de peticiones de [Mithril](https://mithril.js.org/request.html). + +El sistema de peticiones de Flarum está disponible globalmente a través de `app.request(options)`, y tiene las siguientes diferencias con respecto a `m.request(options)` de Mithril: + +- Adjuntará automáticamente las cabeceras `X-CSRF-Token`. +- Convertirá las peticiones `PATCH` y `DELETE` en peticiones `POST`, y adjuntará una cabecera `X-HTTP-Method-Override`. +- Si la petición da error, mostrará una alerta que, si está en modo de depuración, puede ser pulsada para mostrar un modal de error completo. +- Puede proporcionar la opción `background: false`, que ejecutará la petición de forma sincronizada. Sin embargo, esto no debería hacerse casi nunca. + +Por lo demás, la API para utilizar `app.request` es la misma que la de `m.request`. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md new file mode 100644 index 000000000..4add48b70 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md @@ -0,0 +1,215 @@ +# Páginas del frontend y Resolvers + +Como se explica en la documentación de [Rutas y Contenido](routes.md#frontend-routes), podemos utilizar el sistema de rutas de Mithril para mostrar diferentes [componentes](frontend.md#components) para diferentes rutas. Mithril te permite usar cualquier componente que quieras, incluso un Modal o una Alerta, pero recomendamos ceñirse a las clases de componentes que heredan el componente `Page`. + +## El componente de la página + +Proporcionamos `flarum/components/Page` como una clase base para las páginas en los frontends `admin` y `forum`. Tiene algunos beneficios: + +- Actualiza automáticamente [`app.current` y `app.previous` PageState](#pagestate) cuando se cambia de una ruta a otra. +- Cierra automáticamente el modal y el cajón cuando se cambia de una ruta a otra. +- Aplica `this.bodyClass` (si está definido) al elemento HTML '#app' cuando la página se renderiza. +- También es bueno, por coherencia, utilizar una clase base común para todas las páginas. +- Si el atributo `scrollTopOnCreate` de la página se establece en `false` en `oninit`, la página no se desplazará a la parte superior cuando se cambie. +- Si el atributo `useBrowserScrollRestoration` de la página se establece como `false` en `oninit`, la restauración automática del desplazamiento del navegador no se utilizará en esa página. + +Los componentes de página funcionan como cualquier otro componente heredado. Para un ejemplo (muy simple): + +```js +import Page from 'flarum/components/Page'; + + +export default class CustomPage extends Page { + view() { + return

¡Hola!

+ } +} +``` + +### Uso de Resolvers de Rutas + +Flarum uses a setting to determine which page should be the homepage: this gives admins flexibility to customize their communities. To add your custom page to the homepage options in Admin, you'll need to extend the `BasicsPage.homePageItems` method with your page's path. + +Los datos pueden establecerse y recuperarse del estado de la página utilizando: + +```js +import IndexPage from 'flarum/components/DiscussionPage'; +import DiscussionPage from 'flarum/components/DiscussionPage'; + +// Para comprobar sólo el tipo de página +app.current.matches(DiscussionPage); + +// Para comprobar el tipo de página y algunos datos +app.current.matches(IndexPage, {routeName: 'following'}); +``` + +Por ejemplo, así es como la página de discusión hace que su instancia [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) esté disponible globalmente. + +### Resolvers personalizados + +Often, you'll want some custom text to appear in the browser tab's title for your page. For instance, a tags page might want to show "Tags - FORUM NAME", or a discussion page might want to show the title of the discussion. + +To do this, your page should include calls to `app.setTitle()` and `app.setTitleCount()` in its `oncreate` [lifecycle hook](frontend.md) (or when data is loaded, if it pulls in data from the API). + +En realidad hay 3 formas de establecer el componente / resolvedor de rutas cuando se registra una ruta: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + oncreate(vnode) { + super.oncreate(vnode); + + app.setTitle("Cool Page"); + app.setTitleCount(0); + } + + view() { + // ... + } +} + +export default class CustomPageLoadsData extends Page { + oninit(vnode) { + super.oninit(vnode); + + app.store.find("users", 1).then(user => { + app.setTitle(user.displayName()); + app.setTitleCount(0); + }) + } + + view() { + // ... + } +} +``` + +Please note that if your page is [set as the homepage](#setting-page-as-homepage), `app.setTitle()` will clear the title for simplicity. It should still be called though, to prevent titles from previous pages from carrying over. + +## PageState + +A veces, queremos obtener información sobre la página en la que estamos actualmente, o la página de la que acabamos de salir. Para permitir esto, Flarum crea (y almacena) instancias de [`PageState`](https://api.docs.flarum.org/js/master/class/src/common/states/pagestate.js~pagestate) como `app.current` y `app.previous`. Estos almacenan: + +- La clase de componente que se utiliza para la página +- Una colección de datos que cada página establece sobre sí misma. Siempre se incluye el nombre de la ruta actual. + +Data can be set to, and retrieved from, Page State using: + +```js +app.current.set(KEY, DATA); +app.current.get(KEY); +``` + +For example, this is how the Discussion Page makes its [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) instance globally available. + +También se puede comprobar el tipo y los datos de una página utilizando el método `matches` de `PostStreamState`. Por ejemplo, si queremos saber si estamos actualmente en una página de discusión: + +```jsx +import IndexPage from 'flarum/forum/components/DiscussionPage'; +import DiscussionPage from 'flarum/forum/components/DiscussionPage'; + +// To just check page type +app.current.matches(DiscussionPage); + +// To check page type and some data +app.current.matches(IndexPage, {routeName: 'following'}); +``` + +## Resolvers de rutas (avanzado) + +See the [Admin Dashboard documentation](admin.md) for more information on tools specifically available to admin pages (and how to override the admin page for your extension). + +## Route Resolvers (Advanced) + +Los [casos de uso avanzados](https://mithril.js.org/route.html#advanced-component-resolution) pueden aprovechar el [sistema de resolución de rutas](https://mithril.js.org/route.html#routeresolver) de Mithril. En realidad, Flarum ya envuelve todos sus componentes en el resolvedor `flarum/resolvers/DefaultResolver`. Esto tiene los siguientes beneficios: + +- Pasa un attr de `routeName` a la página actual, que lo proporciona a `PageState`. +- Asigna una [clave](https://mithril.js.org/keys.html#single-child-keyed-fragments) al componente de la página de nivel superior. Cuando la ruta cambie, si la clave del componente de nivel superior ha cambiado, se rerenderizará completamente (por defecto, Mithril no rerenderiza los componentes cuando se pasa de una página a otra si ambas son manejadas por el mismo componente). + +### Using Route Resolvers + +There are actually 3 ways to set the component / route resolver when registering a route: + +- la clave `resolver` puede utilizarse para proporcionar una **instancia** de un resolvedor de rutas. Esta instancia debe definir qué componente se debe utilizar, y codificar el nombre de la ruta que se le debe pasar. Esta instancia será utilizada sin ninguna modificación por Flarum. +- Las claves `resolverClass` y `component` pueden utilizarse para proporcionar una **clase** que se utilizará para instanciar un resolvedor de rutas, que se utilizará en lugar del predeterminado por Flarum, así como el componente a utilizar. Su constructor debe tomar 2 argumentos: `(componente, routeName)`. +- La clave `componente` puede utilizarse sola para proporcionar un componente. Esto dará como resultado el comportamiento por defecto. + +Por ejemplo: + +```js +// See above for a custom page example +import CustomPage from './components/CustomPage'; +// See below for a custom resolver example +import CustomPageResolver from './resolvers/CustomPageResolver'; + +// Utilizar una instancia de resolución de rutas +app.routes['resolverInstance'] = {path: '/custom/path/1', resolver: { + onmatch: function(args) { + if (!app.session.user) return m.route.SKIP; + + return CustomPage; + } +}}; + +// Utilizar una clase de resolución de rutas personalizada +app.routes['resolverClass'] = {path: '/custom/path/2', resolverClass: CustomPageResolver, component: CustomPage}; + +// Utilizar la clase de resolución por defecto (`flarum/resolvers/DefaultResolver`) +app.routes['resolverClass'] = {path: '/custom/path/2', component: CustomPage}; +``` + +### Custom Resolvers + +Recomendamos encarecidamente que los resolvedores de rutas personalizados extiendan `flarum/resolvers/DefaultResolver`. Por ejemplo, Flarum's `flarum/resolvers/DiscussionPageResolver` asigna la misma clave a todos los enlaces a la misma discusión (independientemente del post actual), y activa el desplazamiento cuando se utiliza `m.route.set` para ir de un post a otro en la misma página de discusión: + +```js +import DefaultResolver from '../../common/resolvers/DefaultResolver'; + +/** + * This isn't exported as it is a temporary measure. + * A more robust system will be implemented alongside UTF-8 support in beta 15. + */ +function getDiscussionIdFromSlug(slug: string | undefined) { + if (!slug) return; + return slug.split('-')[0]; +} + +/** + * A custom route resolver for DiscussionPage that generates the same key to all posts + * on the same discussion. It triggers a scroll when going from one post to another + * in the same discussion. + */ +export default class DiscussionPageResolver extends DefaultResolver { + static scrollToPostNumber: number | null = null; + + makeKey() { + const params = { ...m.route.param() }; + if ('near' in params) { + delete params.near; + } + params.id = getDiscussionIdFromSlug(params.id); + return this.routeName.replace('.near', '') + JSON.stringify(params); + } + + onmatch(args, requestedPath, route) { + if (route.includes('/d/:id') && getDiscussionIdFromSlug(args.id) === getDiscussionIdFromSlug(m.route.param('id'))) { + DiscussionPageResolver.scrollToPostNumber = parseInt(args.near); + } + + return super.onmatch(args, requestedPath, route); + } + + render(vnode) { + if (DiscussionPageResolver.scrollToPostNumber !== null) { + const number = DiscussionPageResolver.scrollToPostNumber; + // Scroll after a timeout to avoid clashes with the render. + setTimeout(() => app.current.get('stream').goToNumber(number)); + DiscussionPageResolver.scrollToPostNumber = null; + } + + return super.render(vnode); + } +} +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md new file mode 100644 index 000000000..3a686e827 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md @@ -0,0 +1,418 @@ +# Desarrollo del Frontend + +Esta página describe cómo realizar cambios en la interfaz de usuario de Flarum. Cómo añadir botones, marquesinas y texto parpadeante. 🤩 + +[Recuerda](/extend/start.md#architecture), el frontend de Flarum es una **aplicación JavaScript de una sola página**. No hay Twig, Blade, o cualquier otro tipo de plantilla PHP para hablar. Las pocas plantillas que están presentes en el backend sólo se utilizan para renderizar el contenido optimizado para el motor de búsqueda. Todos los cambios en la interfaz de usuario deben hacerse a través de JavaScript. + +Flarum tiene dos aplicaciones frontales separadas: + +* `forum`, el lado público de su foro donde los usuarios crean discusiones y mensajes. +* `admin`, el lado privado de tu foro donde, como administrador de tu foro, configuras tu instalación de Flarum. + +Comparten el mismo código fundacional, así que una vez que sabes cómo extender uno, sabes cómo extender ambos. + +:::tip Typings! + +Along with new TypeScript support, we have a [`tsconfig` package](https://www.npmjs.com/package/flarum-tsconfig) available, which you should install as a dev dependency to gain access to our typings. Make sure you follow the instructions in the [package's README](https://github.com/flarum/flarum-tsconfig#readme) to configure typings support. + +::: + +## Transpilación y estructura de archivos + +Esta parte de la guía explicará la configuración de archivos necesaria para las extensiones. Una vez más, recomendamos encarecidamente utilizar el [generador de extensiones FoF](https://github.com/FriendsOfFlarum/extension-generator) no oficial para configurar la estructura de los archivos por usted. Dicho esto, usted debe leer esto para entender lo que está pasando bajo la superficie. + +Antes de que podamos escribir cualquier JavaScript, necesitamos configurar un **transpilador**. Esto nos permite usar [TypeScript](https://www.typescriptlang.org/) y su magia en el núcleo y las extensiones de Flarum. + +Para hacer esta transpilación, tienes que trabajar en un entorno capaz. No, no se trata de un entorno doméstico o de oficina, ¡puedes trabajar en el baño por lo que a mí respecta! Me refiero a las herramientas instaladas en tu sistema. Necesitarás: + +* Node.js y npm ([Descarga](https://nodejs.org/en/download/)) +* Webpack (`npm install -g webpack`) + +Esto puede ser complicado porque cada sistema es diferente. Desde el sistema operativo que usas, hasta las versiones de los programas que tienes instalados, pasando por los permisos de acceso de los usuarios... ¡me dan escalofríos sólo de pensarlo! Si tienes problemas, ~~dale recuerdos~~ utiliza [Google](https://google.com) para ver si alguien se ha encontrado con el mismo error que tú y ha encontrado una solución. Si no, pide ayuda en la [Comunidad Flarum](https://discuss.flarum.org) o en el [chat de Discord](https://flarum.org/discord/). + +Es hora de configurar nuestro pequeño proyecto de transpilación de JavaScript. Crea una nueva carpeta en tu extensión llamada `js`, y luego introduce un par de archivos nuevos. Una extensión típica tendrá la siguiente estructura de frontend: + +``` +js +├── dist (compiled js is placed here) +├── src +│ ├── admin +│ └── forum +├── admin.js +├── forum.js +├── package.json +└── webpack.config.json +``` + +### package.json + +```json +{ + "private": true, + "name": "@acme/flarum-hello-world", + "dependencies": { + "flarum-webpack-config": "0.1.0-beta.10", + "webpack": "^4.0.0", + "webpack-cli": "^3.0.7" + }, + "scripts": { + "dev": "webpack --mode development --watch", + "build": "webpack --mode production" + } +} +``` + +Este es un [archivo de descripción de paquetes](https://docs.npmjs.com/files/package.json) JS estándar, utilizado por npm y Yarn (gestores de paquetes Javascript). Puedes usarlo para añadir comandos, dependencias js y metadatos del paquete. En realidad no estamos publicando un paquete npm: esto simplemente se utiliza para recoger las dependencias. + +Por favor, ten en cuenta que no necesitamos incluir `flarum/core` o cualquier extensión de flarum como dependencias: se empaquetarán automáticamente cuando Flarum compile los frontales de todas las extensiones. + +### webpack.config.js + +```js +const config = require('flarum-webpack-config'); + +module.exports = config(); +``` + +[Webpack](https://webpack.js.org/concepts/) es el sistema que realmente compila y agrupa todo el javascript (y sus dependencias) para nuestra extensión. Para que funcione correctamente, nuestras extensiones deben utilizar el [official flarum webpack config](https://github.com/flarum/flarum-webpack-config) (mostrado en el ejemplo anterior). + +### tsconfig.json + +```json +{ + // Use Flarum's tsconfig as a starting point + "extends": "flarum-tsconfig", + // This will match all .ts, .tsx, .d.ts, .js, .jsx files in your `src` folder + // and also tells your Typescript server to read core's global typings for + // access to `dayjs` and `$` in the global namespace. + "include": ["src/**/*", "../vendor/flarum/core/js/dist-typings/@types/**/*"], + "compilerOptions": { + // This will output typings to `dist-typings` + "declarationDir": "./dist-typings", + "baseUrl": ".", + "paths": { + "flarum/*": ["../vendor/flarum/core/js/dist-typings/*"] + } + } +} +``` + +This is a standard configuration file to enable support for Typescript with the options that Flarum needs. + +Always ensure you're using the latest version of this file: https://github.com/flarum/flarum-tsconfig#readme. + +A continuación repasaremos las herramientas disponibles para las extensiones. + +To get the typings working, you'll need to run `composer update` in your extension's folder to download the latest copy of Flarum's core into a new `vendor` folder. Remember not to commit this folder if you're using a version control system such as Git. + +You may also need to restart your IDE's TypeScript server. In Visual Studio Code, you can press F1, then type "Restart TypeScript Server" and hit ENTER. This might take a minute to complete. + +### admin.js and forum.js + +Estos archivos contienen la raíz de nuestro frontend JS real. Podrías poner toda tu extensión aquí, pero eso no estaría bien organizado. Por esta razón, recomendamos poner el código en `src`, y que estos archivos sólo exporten el contenido de `src`. Por ejemplo: + +```js +// admin.js +export * from './src/admin'; + +// forum.js +export * from './src/forum'; +``` + +### src + +Si seguimos las recomendaciones para `admin.js` y `forum.js`, querremos tener 2 subcarpetas aquí: una para el código del frontend `admin`, y otra para el código del frontend `forum`. Si tienes componentes, modelos, utilidades u otro código que se comparte en ambos frontends, puedes crear una subcarpeta `common` y colocarla allí. + +La estructura para `admin` y `forum` es idéntica, así que sólo la mostraremos para `forum` aquí: + +``` +src/forum/ +├── components/ +|-- models/ +├── utils/ +└── index.js +``` + +`components`, `models`, y `utils` son directorios que contienen archivos donde puedes definir [componentes](#components), [modelos](data.md#frontend-models), y funciones de ayuda reutilizables. Tenga en cuenta que todo esto es simplemente una recomendación: no hay nada que le obligue a utilizar esta estructura de archivos en particular (o cualquier otra estructura de archivos). + +El archivo más importante aquí es `index.js`: todo lo demás es simplemente extraer clases y funciones en sus propios archivos. Repasemos una estructura típica de archivos `index.js`: + +```js +import {extend, override} from 'flarum/extend'; + +// Proporcionamos nuestro código de extensión en forma de un "inicializador". +// Este es un callback que se ejecutará después de que el núcleo haya arrancado. +app.initializers.add('our-extension', function(app) { + // Su código de extensión aquí + console.log("EXTENSION NAME is working!"); +}); +``` + +We'll go over tools available for extensions below. + +### Transpilación + +:::tip Bibliotecas externas + +Casi todas las extensiones de Flarum necesitarán importar *algo* de Flarum Core. Como la mayoría de las extensiones, el código fuente JS del núcleo está dividido en las carpetas `admin`, `common` y `forum`. Sin embargo, todo se exporta bajo `flarum`. Para elaborar: + +En algunos casos, una extensión puede querer extender el código de otra extensión de flarum. Esto sólo es posible para las extensiones que exportan explícitamente su contenido. + +* `flarum/tags` y `flarum/flags` son actualmente las únicas extensiones empaquetadas que permiten extender su JS. Puedes importar sus contenidos desde `flarum/{EXT_NAME}/PATH` (por ejemplo, `flarum/tags/components/TagHero`). +* The process for extending each community extension is different; you should consult documentation for each individual extension. + +### Transpilation + +Bien, es hora de encender el transpilador. Ejecuta los siguientes comandos en el directorio `js`: + +```bash +npm install +npm run dev +``` + +Esto compilará su código JavaScript listo para el navegador en el archivo `js/dist/forum.js`, y se mantendrá atento a los cambios en los archivos fuente. ¡Genial! + +Cuando hayas terminado de desarrollar tu extensión (o antes de un nuevo lanzamiento), querrás ejecutar `npm run build` en lugar de `npm run dev`: esto construye la extensión en modo de producción, lo que hace que el código fuente sea más pequeño y rápido. + +## Registro de activos + +### JavaScript + +Para que el JavaScript de tu extensión se cargue en el frontend, necesitamos decirle a Flarum dónde encontrarlo. Podemos hacer esto usando el método `js` del extensor `Frontend`. Añádelo al archivo `extend.php` de tu extensión: + +```php +js(__DIR__.'/js/dist/forum.js') +]; +``` + +Flarum hará que cualquier cosa que haga `export` desde `forum.js` esté disponible en el objeto global `flarum.extensions['acme-hello-world']`. Por lo tanto, puede elegir exponer su propia API pública para que otras extensiones interactúen con ella. + +:::tip External Libraries + +Sólo se permite un archivo JavaScript principal por extensión. Si necesitas incluir alguna librería JavaScript externa, instálala con NPM e `import` para que se compile en tu archivo JavaScript, o consulta [Rutas y Contenido](/extend/routes.md) para saber cómo añadir etiquetas `'; + }) +]; +``` + +You can also add content onto your frontend route registrations: + +```php +return [ + (new Extend\Frontend('forum')) + ->route('/users', 'acme.users', function (Document $document, Request $request) { + $document->title = 'Users'; + }) +]; +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/search.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/search.md new file mode 100644 index 000000000..42328c55a --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/search.md @@ -0,0 +1,202 @@ +# Search + +Flarum treats searching and filtering as parallel but distinct processes. Which process is used to handle a request to a [`List` API endpoint](/extend/api.md#api-endpoints) depends on the query parameters: + +- Filtering is applied when the `filter[q]` query param is omitted. Filters represent **structured** queries: for instance, you might want to only retrieve discussions in a certain category, or users who registered before a certain date. Filtering computes results based entirely on `filter[KEY] = VALUE` query parameters. +- Searching is applied when the `filter[q]` query param is included. Searches represent **unstructured** queries: the user submits an arbitrary string, and data records that "match" it are returned. For instance, you might want to search discussions based on the content of their posts, or users based on their username. Searching computes results based solely on parsing the `filter[q]` query param: all other `filter[KEY] = VALUE` params are ignored when searching. It's important to note that searches aren't entirely unstructured: the dataset being searched can be constrained by gambits (which are very similar to filters, and will be explained later). + +This distinction is important because searches and filters have very different use cases: filters represent *browsing*: that is, the user is passively looking through some category of content. In contrast, searches represent, well, *searching*: the user is actively looking for content based on some criteria. + +Flarum implements searching and filtering via per-model `Searcher` and `Filterer` classes (discussed in more detail below). Both classes accept a [`Flarum\Query\QueryCriteria`](https://api.docs.flarum.org/php/master/flarum/query/querycriteria) instance (a wrapper around the user and query params), and return a [`Flarum\Query\QueryResults`](https://api.docs.flarum.org/php/master/flarum/query/queryresults) instance (a wrapper around an Eloquent model collection). This common interface means that adding search/filter support to models is quite easy. + +One key advantage of this split is that it allows searching to be implemented via an external service, such as ElasticSearch. For larger communities, this can be significantly more performant and accurate. There isn't a dedicated extender for this yet, so for now, replacing the default Flarum search driver requires overriding the container bindings of `Searcher` classes. This is a highly advanced use case; if you're interested in doing this, please reach out on our [community forums](https://discuss.flarum.org/). + +Remember that the [JSON:API schema](https://jsonapi.org/format) is used for all API requests. + +:::tip Reuse Code + +Often, you might want to use the same class as both a `Filter` and a `Gambit` (both explained below). Your classes can implement both interface; see Flarum core's [`UnreadFilterGambit`](https://github.com/flarum/framework/blob/main/framework/core/src/Discussion/Query/UnreadFilterGambit.php) for an example. + +::: + +:::tip Query Builder vs Eloquent Builder + +`Filter`s, `Gambit`s, filter mutators, and gambit mutators (all explained below) receive a "state" parameter, which wraps + +::: + +## Filtering + +Filtering constrains queries based on `Filters` (highlighted in code to avoid confusion with the process of filtering), which are classes that implement `Flarum\Filter\FilterInterface` and run depending on query parameters. After filtering is complete, a set of callbacks called "filter mutators" run for every filter request. + +When the `filter` method on a `Filterer` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Filter/AbstractFilterer.php#L50-L93)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Filterer` class's `getQuery()` method. +2. We loop through all `filter[KEY] = VALUE` query params. For each of these, any `Filter`s registered to the model whose `getFilterKey()` method matches the query param `KEY` is applied. `Filter`s can be negated by providing the query param as `filter[-KEY] = VALUE`. Whether or not a `Filter` is negated is passed to it as an argument: implementing negation is up to the `Filter`s. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "filter mutators" are applied. These are callbacks that receive the filter state (a wrapper around the query builder and current user) and filter criteria, and perform some arbitrary changes. All "filter mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Filtering for an Existing Model + +Let's say you've added a `country` column to the User model, and would like to filter users by country. We'll need to define a custom `Filter`: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +Note that `FilterState` is a wrapper around the Eloquent builder's underlying Query builder and the current user. + +Also, let's pretend that for some reason, we want to omit any users that have a different country from the current user on ANY filter. We can use a "filter mutator" for this: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +Now, all we need to do is register these via the Filter extender: + +```php + // Other extenders + (new Extend\Filter(UserFilterer::class)) + ->addFilter(CountryFilter::class) + ->addFilterMutator(OnlySameCountryFilterMutator::class), + // Other extenders +``` + +### Add Filtering to a New Model + +To filter a model that doesn't support filtering, you'll need to create a subclass of `Flarum/Filter/AbstractFilterer` for that model. For an example, see core's [UserFilterer](https://github.com/flarum/framework/blob/main/framework/core/src/User/Filter/UserFilterer.php). + +Then, you'll need to use that filterer in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +## Searching + +Searching constrains queries by applying `Gambit`s, which are classes that implement `Flarum\Search\GambitInterface`, based on the `filter[q]` query param. After searching is complete, a set of callbacks called "search mutators" run for every search request. + +When the `search` method on a `Searcher` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Search/AbstractSearcher.php#L55-L79)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Searcher` class's `getQuery()` method. +2. The `filter[q]` param is split by spaces into "tokens". Each token is matched against the model's registered `Gambit`s (each gambit has a `match` method). For any tokens that match a gambit, that gambit is applied, and the token is removed from the query string. Once all regular `Gambit`s have ran, all remaining unmatched tokens are passed to the model's `FullTextGambit`, which implements the actual searching logic. For example if searching discussions, in the `filter[q]` string `'author:1 hello is:hidden' world`, `author:1` and `is:hidden` would get matched by core's Author and Hidden gambits, and `'hello world'` (the remaining tokens) would be passed to the `DiscussionFulltextGambit`. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "search mutators" are applied. These are callbacks that receive the search state (a wrapper around the query builder and current user) and criteria, and perform some arbitrary changes. All "search mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Searching for an Existing Model + +Let's reuse the "country" examples we used above, and see how we'd implement the same things for searching: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +:::warning No Spaces in Gambit Patterns! + +Flarum splits the `filter[q]` string into tokens by splitting it at spaces. This means that your custom gambits can NOT use spaces as part of their pattern. + +::: + +:::tip AbstractRegexGambit + +All a gambit needs to do is implement `Flarum\Search\GambitInterface`, which receives the search state and a token. It should return if this gambit applies for the given token, and if so, make whatever mutations are necessary to the query builder accessible as `$searchState->getQuery()`. + +However, for most gambits, the `AbstractRegexGambit` abstract class (used above) should be used as a base class. This makes it a lot simpler to match and apply gambits. + +::: + +Similarly, the search mutator we need is almost identical to the filter mutator from before: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +We can register these via the `SimpleFlarumSearch` extender (in the future, the `Search` extender will be used for registering custom search drivers): + +```php + // Other extenders + (new Extend\SimpleFlarumSearch(UserSearcher::class)) + ->addGambit(CountryGambit::class) + ->addSearchMutator(OnlySameCountrySearchMutator::class), + // Other extenders +``` + +### Add Searching to a New Model + +To support searching for a model, you'll need to create a subclass of `Flarum/Search/AbstractSearcher` for that model. For an example, see core's [UserSearcher](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/UserSearcher.php). + +Then, you'll need to use that searcher in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +Every searcher **must** have a fulltext gambit (the logic that actually does the searching). Otherwise, it won't be booted by Flarum, and you'll get an error. See core's [FulltextGambit for users](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/Gambit/FulltextGambit.php) for an example. You can set (or override) the full text gambit for a searcher via the `SimpleFlarumSearch` extender's `setFullTextGambit()` method. + +### Search Drivers + +Coming soon! + +## Frontend Tools + +Coming soon! diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md new file mode 100644 index 000000000..ee4370f58 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md @@ -0,0 +1,65 @@ +# Proveedor de servicios + +Como se ha señalado a lo largo de esta documentación, Flarum utiliza [el contenedor de servicios de Laravel](https://laravel.com/docs/6.x/container) (o contenedor IoC) para la inyección de dependencias. Los [Service Providers](https://laravel.com/docs/6.x/providers) permiten la configuración y modificación de bajo nivel del backend de Flarum. El caso de uso más común para los proveedores de servicio es crear, modificar o reemplazar los enlaces del contenedor. Dicho esto, los proveedores de servicios le permiten un acceso completo para ejecutar cualquier lógica que necesite durante el arranque de la aplicación con acceso al contenedor. + +:::caution ¡¡¡Sólo para uso avanzado!!! + +A diferencia de otros extensores, la capa del proveedor de servicios NO está orientada a los casos de uso y NO se considera una API pública. Está sujeta a cambios en cualquier momento, sin previo aviso o depreciación. Esto sólo debe ser utilizado si usted sabe lo que está haciendo, y los otros extensores no satisfacen su caso de uso. + +::: + +## Proceso de arranque de Flarum + +Para entender los proveedores de servicios, primero hay que entender el orden en que Flarum arranca. Most of this happens in [Flarum\Foundation\InstalledSite](https://github.com/flarum/framework/blob/main/framework/core/src/Foundation/InstalledSite.php) + +1. El contenedor y la aplicación se inicializan, y se registran los bindings esenciales (config, environment, logger) +2. Se ejecutan los métodos `register` de todos los proveedores de servicios esenciales. +3. Se ejecutan los métodos `extend` de todos los extensores utilizados por todas las extensiones habilitadas. +4. Se ejecutan los métodos `extend` de todos los extensores utilizados en el sitio local de Flarum `extend.php`. +5. Se ejecutan los métodos `boot` de todos los proveedores de servicios centrales. + +## Proveedores de servicios personalizados + +Un proveedor de servicios personalizado debe extender `Flarum\Foundation\AbstractServiceProvider`, y puede tener un método `boot` y otro `register`. Por ejemplo: + +```php +container->resolving(SomeClass::class, function ($container) { + return new SomeClass($container->make('some.binding')); + }); + } + + public function boot(Container $container) + { + // custom logic here + } +} +``` + +El método `register` se ejecutará durante el paso (3) anterior, y el método `boot` se ejecutará durante el paso (5) anterior. En ambos métodos, el contenedor está disponible a través de `$this->app`. In the `boot` method, the container (or any other arguments), should be injected via typehinted method arguments. + +Flarum does not currently support Laravel Octane, but some [best practices](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane), like using the `$container` argument inside `bind`, `singleton`, and `resolving` callbacks instead of `$this->container` should be used. See the [Octane documentation](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane) for more information. + +Para registrar tu proveedor de servicios personalizado, puedes usar el extensor `ServiceProvider` en `extend.php`: + +```php +register(CustomServiceProvider::class), + // Otros extensores +]; +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/settings.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/settings.md new file mode 100644 index 000000000..e29999653 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/settings.md @@ -0,0 +1,90 @@ +# Ajustes + +En algún momento mientras haces una extensión, puede que quieras leer algunas de las configuraciones del foro o almacenar ciertas configuraciones específicas de tu extensión. Afortunadamente, Flarum hace esto muy fácil. + +## El repositorio de ajustes + +La lectura o el cambio de configuraciones puede hacerse usando una implementación de la `SettingsRepositoryInterface`. En su lugar, puedes confiar en el contenedor para instanciar tu clase e inyectar las dependencias correctas. Debido a que Flarum utiliza el [contenedor de servicios de Laravel](https://laravel.com/docs/6.x/container) (o contenedor IoC) para la inyección de dependencias, no necesitas preocuparte de dónde obtener tal repositorio, o cómo instanciar uno. + +```php +settings = $settings; + } +} +``` + +Muy bien. Ahora la `SettingsRepositoryInterface` está disponible a través de `$this->settings` para nuestra clase. + +### Lectura de la configuración + +Para leer la configuración, todo lo que tenemos que hacer es utilizar la función `get()` del repositorio: + +`$this->settings->get('forum_title')` + +La función `get()` acepta dos argumentos: + +1. El nombre de la configuración que está tratando de leer. +2. (Opcional) Un valor por defecto si no se ha almacenado ningún valor para dicho ajuste. Por defecto, será `null`. + +### Almacenamiento de ajustes + +Almacenar configuraciones es igual de fácil, utilice la función `set()`: + +`$this->settings->set('forum_title', 'Super Awesome Forum')` + +La función `set` también acepta dos argumentos: + +1. El nombre de la configuración que está tratando de cambiar. +2. El valor que desea almacenar para este ajuste. + +### Otras Funciones + +La función `all()` devuelve una matriz con todas las configuraciones conocidas. + +La función `delete($name)` permite eliminar una configuración con nombre. + +## Ajustes en el Frontend + +### Edición de Ajustes + +Para obtener más información sobre la gestión de la configuración a través del panel de administración, consulte la [documentación pertinente](admin.md). +### Acceso a la Configuración + +Todos los ajustes están disponibles en el frontend `admin` a través del global `app.data.settings`. Sin embargo, esto no se hace en el frontend `forum`, ya que cualquiera puede acceder a él, ¡y no querrías filtrar todas tus configuraciones! (En serio, eso podría ser una violación de datos muy problemática). (Seriously, that could be a very problematic data breach). + +En su lugar, si queremos utilizar la configuración en el frontend de `forum`, tendremos que serializarla y enviarla junto con la carga de datos inicial del foro. + +Esto se puede hacer a través del extensor `Settings`. Por ejemplo: + +**extend.php** + +```php +use Flarum\Extend; + +return [ + (new Extend\Settings) + ->serializeToForum('myCoolSetting', 'my.cool.setting.key') + ->serializeToForum('myCoolSettingModified', 'my.cool.setting.key', function ($retrievedValue) { + // Este tercer argumento es opcional, y nos permite pasar la configuración recuperada a través de alguna lógica personalizada. + // En este ejemplo, le añadiremos una cadena. + + return "My Cool Setting: $retrievedValue"; + }), +] +``` + +Ahora, el ajuste `my.cool.setting.key` será accesible en el frontend como `app.forum.attribute("myCoolSetting")`, y nuestro valor modificado será accesible a través de `app.forum.attribute("myCoolSettingModified")`. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md new file mode 100644 index 000000000..3dc39416b --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md @@ -0,0 +1 @@ +# Model Slugging diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/start.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/start.md new file mode 100644 index 000000000..91c58ff53 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/start.md @@ -0,0 +1,153 @@ +# Cómo empezar + +¿Quieres construir una extensión de Flarum? You've come to the right place! ¡Has venido al lugar correcto! Este documento te llevará a través de algunos conceptos esenciales, después de lo cual construirás tu primera extensión de Flarum desde cero. + +## Arquitectura + +Para entender cómo extender Flarum, primero necesitamos entender un poco cómo está construido Flarum. + +Ten en cuenta que Flarum utiliza algunos lenguajes y herramientas _modernas_. Si sólo has construido plugins para WordPress antes, puede que te sientas un poco fuera de tu alcance. No pasa nada, es un buen momento para aprender cosas nuevas y ampliar tus conocimientos. Sin embargo, te aconsejamos que te familiarices con las tecnologías descritas a continuación antes de continuar. + +Flarum se compone de tres capas: + +* En primer lugar, está el **backend**. Está escrito en [PHP orientado a objetos](https://laracasts.com/series/object-oriented-bootcamp-in-php), y hace uso de una amplia gama de componentes de [Laravel](https://laravel.com/) y otros paquetes a través de [Composer](https://getcomposer.org/). También querrás familiarizarte con el concepto de [Dependency Injection](https://laravel.com/docs/6.x/container), que se utiliza en todo nuestro backend. + +* En segundo lugar, el backend expone una **API pública** que permite a los clientes del frontend interactuar con los datos de tu foro. Está construida de acuerdo con la especificación [JSON:API](https://jsonapi.org/). + +* Por último, está la interfaz web por defecto que llamamos **frontend**. Esta es una [single-page application](https://en.wikipedia.org/wiki/Single-page_application) que consume la API. Está construida con un sencillo framework tipo React llamado [Mithril.js](https://mithril.js.org). + +Las extensiones a menudo necesitarán interactuar con estas tres capas para hacer que las cosas sucedan. Por ejemplo, si quieres construir una extensión que añada campos personalizados a los perfiles de los usuarios, tendrías que añadir las estructuras de base de datos apropiadas en el **backend**, exponer esos datos en la **public API**, y luego mostrarlos y permitir a los usuarios editarlos en el **frontend**. + +Así que... ¿cómo extendemos estas capas? + +## Extensores + +Para extender Flarum, usaremos un concepto llamado **extensores**. Los extensores son objetos *declarativos* que describen en términos sencillos los objetivos que se pretenden alcanzar (como añadir una nueva ruta a tu foro, o ejecutar algún código cuando se crea una nueva discusión). + +Cada extensor es diferente. Sin embargo, siempre tendrán un aspecto similar a este: + +```php +// Registrar un archivo JavaScript y un archivo CSS para ser entregado con el frontend del foro +(new Extend\Frontend('forum')) + ->js(__DIR__.'/forum-scripts.js') + ->css(__DIR__.'/forum-styles.css') +``` + +Primero se crea una instancia del extensor, y luego se llama a los métodos en él para la configuración adicional. Todos estos métodos devuelven el propio extensor, de modo que puedes conseguir toda la configuración simplemente encadenando llamadas a métodos. + +Para mantener la coherencia, utilizamos este concepto de extensores tanto en el backend (en la tierra de PHP) como en el frontend (en la tierra de JavaScript). _Todo_ lo que haga en su extensión debe ser hecho a través de extensores, porque son una **garantía** que le estamos dando de que una futura versión menor de Flarum no romperá su extensión. + +All of the extenders currently available to you from Flarum's core can be found in the [`Extend` namespace](https://github.com/flarum/framework/blob/main/framework/core/src/Extend) [(PHP API documentation)](https://api.docs.flarum.org/php/master/flarum/extend) Extensions may also offer their [own extenders](extensibility.md#custom-extenders). + +## Hola Mundo + +¿Quieres ver un extensor en acción? El archivo `extend.php` en la raíz de tu instalación de Flarum es la forma más fácil de registrar extensores sólo para tu sitio. Debería devolver un array de objetos extensores. Ábrelo y añade lo siguiente: + +```php +content(function (Document $document) { + $document->head[] = ''; + }) +]; +``` + +Ahora haz una visita a tu foro para un agradable (aunque extremadamente molesto) saludo. 👋 + +Para personalizaciones sencillas específicas del sitio -como añadir un poco de CSS/JavaScript personalizado, o integrarse con el sistema de autenticación de tu sitio- el archivo `extend.php` en la raíz de tu foro es genial. Pero en algún momento, tu personalización podría superarlo. O tal vez hayas querido construir una extensión para compartirla con la comunidad desde el principio. ¡Es hora de construir una extensión! + +## Empaquetado de extensiones + +[Composer](https://getcomposer.org) es un gestor de dependencias para PHP. Permite a las aplicaciones tirar fácilmente de las bibliotecas de código externas y hace que sea fácil mantenerlas actualizadas para que la seguridad y las correcciones de errores se propaguen rápidamente. + +Resulta que cada extensión de Flarum es también un paquete de Composer. Eso significa que la instalación de Flarum de alguien puede "requerir" una determinada extensión y Composer la traerá y la mantendrá actualizada. Muy bien. + +Durante el desarrollo, puedes trabajar en tus extensiones localmente y configurar un [repositorio de rutas de Composer](https://getcomposer.org/doc/05-repositories.md#path) para instalar tu copia local. Crea una nueva carpeta `packages` en la raíz de tu instalación de Flarum, y luego ejecuta este comando para decirle a Composer que puede encontrar paquetes aquí: + +```bash +composer config repositories.0 path "packages/*" +``` + +Ahora vamos a empezar a construir nuestra primera extensión. Crea una nueva carpeta dentro de `packages` para tu extensión llamada `hello-world`. Pondremos dos archivos en ella: `extend.php` y `composer.json`. Estos archivos sirven como el corazón y el alma de la extensión. + +### extend.php + +El archivo `extend.php` es igual que el que está en la raíz de su sitio. Devolverá un array de objetos extensor que le dicen a Flarum lo que quieres hacer. Por ahora, solo mueve el extensor `Frontend` que tenías antes. + +### composer.json + +Necesitamos decirle a Composer un poco sobre nuestro paquete, y podemos hacerlo creando un archivo `composer.json`: + +```json +{ + "name": "acme/flarum-hello-world", + "description": "Say hello to the world!", + "type": "flarum-extension", + "require": { + "flarum/core": ">=0.1.0-beta.15 <0.1.0-beta.16" + }, + "autoload": { + "psr-4": {"Acme\\HelloWorld\\": "src/"} + }, + "extra": { + "flarum-extension": { + "title": "Hello World", + "icon": { + "name": "fas fa-smile", + "backgroundColor": "#238c59", + "color": "#fff" + } + } + } +} +``` + +* **name** es el nombre del paquete de Composer en el formato `vendedor/paquete`. + * Debes elegir un nombre de proveedor que sea único para ti - tu nombre de usuario de GitHub, por ejemplo. Para los propósitos de este tutorial, asumiremos que estás usando `acme` como tu nombre de proveedor. + * Debes anteponer a la parte del `package` el prefijo `flarum-` para indicar que se trata de un paquete específicamente destinado a ser utilizado con Flarum. + +* **description** es una breve descripción de una frase de lo que hace la extensión. + +* **type** debe ser establecido como `flarum-extension`. Esto asegura que cuando alguien "requiera" su extensión, será identificada como tal. + +* **require** contiene una lista de las dependencias propias de su extensión. + * Querrá especificar la versión de Flarum con la que su extensión es compatible aquí. + * Este es también el lugar para listar otras bibliotecas de Composer que su código necesita para funcionar. + +* **autoload** indica a Composer dónde encontrar las clases de su extensión. El espacio de nombres aquí debe reflejar el nombre del proveedor y del paquete de su extensión en CamelCase. + +* **extra.flarum-extension** contiene alguna información específica de Flarum, como el nombre de su extensión y el aspecto de su icono. + * **title** es el nombre de su extensión. + * **icon** es un objeto que define el icono de tu extensión. La propiedad **name** es un [nombre de clase de icono de Font Awesome](https://fontawesome.com/icons). Todas las demás propiedades se utilizan como el atributo `style` para el icono de su extensión. + +Consulte [el esquema composer.json](https://getcomposer.org/doc/04-schema.md) para obtener información sobre otras propiedades que puede añadir a `composer.json`. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +Utilice el [FoF extension generator](https://github.com/FriendsOfFlarum/extension-generator) para crear automáticamente el andamiaje de su extensión. +```bash +$ flarum-cli init +``` + +::: + +### Instalación de la extensión + +Lo último que tenemos que hacer para empezar a funcionar es instalar tu extensión. Navega al directorio raíz de tu instalación de Flarum y ejecuta el siguiente comando: + +```bash +composer require acme/flarum-hello-world *@dev +``` + +Una vez hecho esto, sigue adelante y activa la extension en la página de administración de tu foro, luego navega de nuevo a tu foro. + +*whizzing, whirring, metal clunking* + +Woop! Hello to you too, extension! + +Estamos haciendo buenos progresos. Hemos aprendido a configurar nuestra extensión y a utilizar los extensores, lo que nos abre muchas puertas. Sigue leyendo para aprender a extender el frontend de Flarum. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md new file mode 100644 index 000000000..fe879c026 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md @@ -0,0 +1,86 @@ +# Static Code Analysis + +Static code analysis is the process of analyzing the source code against a set of rules to find bugs, code smells, and security vulnerabilities. This is a great way to improve the quality of your code and to find potential issues before they are deployed to production. An example is validating the typings of a function to ensure that the function is called with the correct arguments. + +Flarum provides a static code analysis package based on [PHPStan](https://phpstan.org/) that can be added to your extension. In this guide, we will show you how to add the package to your extension and how to run the analysis. + +## Configuración + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update the infrastructure for phpstan to your code: + +```bash +$ flarum-cli infra phpstan +``` + +::: + +First you need to require the `flarum/phpstan` package in your extension. You can do this by running the following command in the root of our extension: + +```bash +composer require --dev flarum/phpstan:^1.0 +``` + +Next, you need to create a `phpstan.neon` file in the root of your extension. This file contains [the configuration for PHPStan](https://phpstan.org/config-reference). You can copy the following configuration into the file: + +```neon +includes: + - vendor/flarum/phpstan/extension.neon + +parameters: + # The level will be increased in Flarum 2.0 + level: 5 + paths: + - src + - extend.php + excludePaths: + - *.blade.php + checkMissingIterableValueType: false + databaseMigrationsPath: ['migrations'] +``` + +Finally, you need to add the following script to your `composer.json` file: + +```json +{ + "scripts": { + "analyse:phpstan": "phpstan analyse", + "clear-cache:phpstan": "phpstan clear-result-cache" + }, + "scripts-descriptions": { + "analyse:phpstan": "Run static analysis" + } +} +``` + +## Running the analysis + +To run the analysis, you can run the following command in the root of your extension: + +```bash +composer analyse:phpstan +``` + +If you want to clear the cache before running the analysis, you can run the following command: + +```bash +composer clear-cache:phpstan && composer analyse:phpstan +``` + +## GitHub Actions + +You can also run the analysis using GitHub Actions. Checkout the page on [GitHub Actions](github-actions.md) for more information. + +## Tips + +### Extended model attribute types + +PHPStan needs to be able to determine the type of an attribute added to an existing model. To do this you can use the `Extend\Model(...)->cast(...)` method. + +For example, if your extension were to add a `is_cool` attribute to the `User` model, you can use [attribute casting](https://laravel.com/docs/8.x/eloquent-mutators#attribute-casting) to explicitly define the attribute as boolean. The `flarum/phpstan` package will automatically detect this and communicate it to PHPStan. + +```php +(new Extend\Model(User::class)) + ->cast('is_cool', 'bool'), +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/testing.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/testing.md new file mode 100644 index 000000000..838725732 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/testing.md @@ -0,0 +1,565 @@ +# Testing + +Las pruebas automatizadas garantizan que tu extensión funcione como esperas, ayudan a evitar la introducción de nuevos errores o regresiones, y ahorran tiempo en las pruebas manuales. Actualmente, Flarum proporciona herramientas para las pruebas unitarias y de integración automatizadas del backend, y planeamos lanzar soporte para las pruebas unitarias del frontend y las pruebas E2E en el futuro. + +## Backend Tests + +La librería `flarum/testing` es utilizada por el núcleo y algunas extensiones para realizar pruebas unitarias y de integración automatizadas. Es esencialmente una colección de utilidades que permiten probar el núcleo y las extensiones de Flarum con PHPUnit. + +### Configuración + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update backend testing infrastructure to your code: + +```bash +$ flarum-cli infra backendTesting +``` + +::: + +```bash +composer require --dev flarum/testing:^1.0 +``` + +Then, you will need to set up a file structure for tests, and add PHPUnit configuration: + +``` +tests +├── fixtures (put any files needed by your tests here (blade templates, images, etc)) +├── integration +│ ├── setup.php (code below) +│ └── PUT INTEGRATION TESTS HERE (organizing into folder is generally a good idea) +├── unit +│ ├── PUT UNIT TESTS HERE +├── phpunit.integration.xml (code below) +└── phpunit.unit.xml (code below) +``` + +#### phpunit.integration.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for integration tests. You can tweak this as needed, but keep `backupGlobals`, `backupStaticAttributes`, and `processIsolation` unchanged. + +```xml + + + + + + + ./integration + + + +``` + +#### phpunit.unit.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for unit tests. You can tweak this as needed. + +```xml + + + + + + + ./unit + + + + + + +``` + +#### setup.php + +This script will be run to set up a testing database / file structure. + +```php +run(); +``` + +#### composer.json Modificaciones + +We will also want to add scripts to our `composer.json`, so that we can run our test suite via `composer test`. Add some variant of the following to your `composer.json`: + +```json +"scripts": { + "test": [ + "@test:unit", + "@test:integration" + ], + "test:unit": "phpunit -c tests/phpunit.unit.xml", + "test:integration": "phpunit -c tests/phpunit.integration.xml", + "test:setup": "@php tests/integration/setup.php" +}, +"scripts-descriptions": { + "test": "Runs all tests.", + "test:unit": "Runs all unit tests.", + "test:integration": "Runs all integration tests.", + "test:setup": "Sets up a database for use with integration tests. Execute this only once." +} +``` + +#### Flujo de trabajo de pruebas en Github + +To run tests on every commit and pull request, check out the [GitHub Actions](github-actions.md) page. + +--- + +Now that we have everything in place, we need to set up our testing site for integration tests. For this, we will need a MySQL or MariaDb instance, and a place to store testing files. + +Testing database information is configured via the `DB_HOST` (defaults to `localhost`), `DB_PORT` (defaults to `3306`), `DB_DATABASE` (defaults to `flarum_test`), `DB_USERNAME` (defaults to `root`), `DB_PASSWORD` (defaults to `root`), and `DB_PREFIX` (defaults to `''`) environmental variables. The testing tmp directory path is configured via the `FLARUM_TEST_TMP_DIR_LOCAL` or `FLARUM_TEST_TMP_DIR` environmental variables, with the former taking precedence over the latter. If neither are provided, a `tmp` directory will be created in the `vendor` folder of your extension's local install. + +Now that we've provided the needed information, all we need to do is run `composer test:setup` in our extension's root directory, and we have our testing environment ready to go! + +Since [(almost)](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/tests/integration/api/discussions/ListWithFulltextSearchTest.php#L29-L45) all database operations in integration tests are run in transactions, developers working on multiple extensions will generally find it more convenient to use one shared database and tmp directory for testing all their extensions. To do this, set the database config and `FLARUM_TEST_TMP_DIR` environmental variables in your `.bashrc` or `.bash_profile` to the path you want to use, and run the setup script for any one extension (you'll still want to include the setup file in every repo for CI testing via GitHub Actions). You should then be good to go for any Flarum extension (or core). + +### Uso de las pruebas de integración + +Flarum's integration test utils are contained in the `Flarum\Testing\integration\TestCase` class. It: + +- Inicia (y hace disponible) una instancia de la aplicación Flarum. +- Permite prepoblar la base de datos, habilitar extensiones y añadir extensores. +- Ejecuta todos los cambios de la base de datos en las transacciones, por lo que su base de datos de prueba conserva el estado predeterminado después de la instalación. +- Permite enviar solicitudes a través de la pila de middleware para probar los puntos finales HTTP. + +Your testcase classes should extend this class. + +#### Configuración de casos de prueba + +There are several important utilities available for your test cases: + +- The `setting($key, $value)` method allows you to override settings before the app has booted. This is useful if your boot process has logic depending on settings (e.g. which driver to use for some system). +- Similarly, the `config($key, $value)` method allows you to override config.php values before the app has booted. You can use dot-delimited keys to set deep-nested values in the config array. +- El método `extension()` tomará los IDs de Flarum de las extensiones a habilitar como argumentos. Su extensión siempre debe llamar a esto con el ID de su extensión al comienzo de los casos de prueba, a menos que el objetivo del caso de prueba en cuestión sea confirmar algún comportamiento presente sin su extensión, y compararlo con el comportamiento cuando su extensión está habilitada. Si su extensión depende de otras extensiones, asegúrese de que están incluidas en el campo `require` de composer.json (o `require-dev` para [dependencias opcionales](dependencies.md)), y también liste los nombres de sus paquetes en composer cuando llame a `extension()`. Ten en cuenta que debes listarlos en un orden válido. +- El método `extend()` toma instancias de extensores como argumentos, y es útil para probar extensores introducidos por su extensión para que otras extensiones los usen. +- El método `prepareDatabase()` le permite pre-poblar su base de datos. Esto podría incluir la adición de usuarios, discusiones, mensajes, configuración de permisos, etc. Su argumento es un array asociativo que mapea los nombres de las tablas a arrays de [arrays de registros](https://laravel.com/docs/8.x/queries#insert-statements). + +If your test case needs users beyond the default admin user, you can use the `$this->normalUser()` method of the `Flarum\Testing\integration\RetrievesAuthorizedUsers` trait. + +:::warning + +The `TestCase` class will boot a Flarum instance the first time its `app()` method is called. Any uses of `prepareDatabase`, `extend`, or `extension` after this happens will have no effect. Make sure you have done all the setup you need in your test case before calling `app()`, or `database()`, `server()`, or `send()`, which call `app()` implicitly. If you need to make database modifications after the app has booted, you can use the regular Eloquent save method, or the `Illuminate\Database\ConnectionInterface` instance obtained via calling the `database()` method. + +::: + +Of course, since this is all based on PHPUnit, you can use the `setUp()` methods of your test classes for common setup tasks. + +Por ejemplo: + +```php +setting('my.custom.setting', true); + + // Let's assume our extension depends on tags. + // Note that tags will need to be in your extension's composer.json's `require-dev`. + // Also, make sure you include the ID of the extension currently being tested, unless you're + // testing the baseline without your extension. + $this->extension('flarum-tags', 'my-cool-extension'); + + // Note that this input isn't validated: make sure you're populating with valid, representative data. + $this->prepareDatabase([ + 'users' => [ + $this->normalUser() // Available for convenience. + ], + 'discussions' => [ + ['id' => 1, 'title' => 'some title', 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 1, 'first_post_id' => 1, 'comment_count' => 1] + ], + 'posts' => [ + ['id' => 1, 'number' => 1, 'discussion_id' => 1, 'created_at' => Carbon::now(), 'user_id' => 1, 'type' => 'comment', 'content' => '

something

'] + ] + ]); + + // Most test cases won't need to test extenders, but if you want to, you can. + $this->extend((new CoolExtensionExtender)->doSomething('hello world')); + } + + /** + * @test + */ + public function some_phpunit_test_case() + { + // ... + } + + // ... +} +``` + +#### Envío de solicitudes + +A common application of automated testing is pinging various HTTP endpoints with various data, authenticated as different users. You can use this to ensure that: + +- Los usuarios no pueden acceder a contenidos a los que no están autorizados a acceder. +- Las operaciones de creación/edición/borrado basadas en permisos funcionan como se espera. +- El tipo y el esquema de los datos devueltos son correctos. +- Se aplica algún efecto secundario deseado al hacer ping a una API. +- Las operaciones básicas de la API que necesita tu extensión no dan errores y no se rompen cuando haces cambios. + +`TestCase` provides several utilities: + +- El método `request()` construye un objeto de implementación `Psr\Http\Message\ServerRequestInterface` a partir de una ruta, un método, y algunas opciones, que pueden utilizarse para la autenticación, adjuntar cookies, o configurar el cuerpo de la petición JSON. Consulta el [method docblock](https://github.com/flarum/testing/blob/main/src/integration/TestCase.php) para obtener más información sobre las opciones disponibles. +- Una vez que hayas creado una instancia de petición, puedes enviarla (y obtener un objeto de respuesta de vuelta) a través del método `send()`. + +Por ejemplo: + +```php +send( + $this->request('GET', '/api/users', ['authenticatedAs' => 1]) + ->withQueryParams(['filter' => ['q' => 'john group:1'], 'sort' => 'username']) + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + /** + * @test + */ + public function can_create_user() + { + $response = $this->send( + $this->request( + 'POST', + '/api/users', + [ + 'authenticatedAs' => 1, + 'json' => [ + 'data' => [ + 'attributes' => [ + 'username' => 'test', + 'password' => 'too-obscure', + 'email' => 'test@machine.local' + ] + ] + ] + ] + ) + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + // ... +} +``` + +:::caution + +If you want to send query parameters in a GET request, you can't include them in the path; you'll need to add them afterwards with the `withQueryParams` method. + +::: + +:::caution + +This is an extreme edge case, but note that MySQL does not update the fulltext index in transactions, so the standard approach won't work if you're trying to test a modified fulltext query. See [core's approach](https://github.com/flarum/framework/blob/main/framework/core/tests/integration/extenders/SimpleFlarumSearchTest.php) for an example of a workaround. + +::: + +#### Pruebas de consola + +If you want to test custom console commands, you can extend `Flarum\Testing\integration\ConsoleTestCase` (which itself extends the regular `Flarum\Testing\integration\TestCase`). It provides 2 useful methods: + +- `$this->console()` devuelve una instancia de `Symfony\Component\Console\Application`. +- `$this->runCommand()` toma un array que será envuelto en `Symfony\Component\ConsoleInput\ArrayInput`, y lo ejecuta. Para más información, consulte el [bloque de documentos de código Symfony](https://github.com/symfony/console/blob/5.x/Input/ArrayInput.php#L22). + +Por ejemplo: + +```php + 'some:command', // The command name, equivalent of `php flarum some:command` + 'foo' => 'bar', // arguments + '--lorem' => 'ipsum' // options + ]; + + $this->assertEquals('Some Output.', $this->runCommand($input)); + } +} +``` + +### Using Unit Tests + +Unit testing in Flarum uses [PHPUnit](https://phpunit.de/getting-started/phpunit-9.html) and so unit testing in flarum is much like any other PHP application. You can find [general tutorials on testing](https://www.youtube.com/watch?v=9-X_b_fxmRM) if you're also new to php. + +When writing unit tests in Flarum, here are some helpful tips. + +#### Mocking Flarum Services + +Unlike the running app, or even integration tests, there is no app/container/etc to inject service instances into our classes. Now all the useful settings, or helpers your extension use require a _mock_ . We want to limit mocking to just the key services, supporting only the minimum interactions needed to test the contract of our individual functions. + +```php + public function setUp(): void + { + parent::setUp(); + // example - if our setting needs settings, we can mock the settings repository + $settingsRepo = m::mock(SettingsRepositoryInterface::class); + // and then control specific return values for each setting key + $settingsRepo->shouldReceive('get')->with('some-plugin-key')->andReturn('some-value-useful-for-testing'); + // construct your class under test, passing mocked services as needed + $this->serializer = new YourClassUnderTest($settingsRepo); + } +``` + +Some aspects require more mocks. If you're validating authorization interactions for instance you might need to mock your users `User::class` and the request's method that provides them as well! + +``` + $this->actor = m::mock(User::class); + $request = m::mock(Request::class)->makePartial(); + $request->shouldReceive('getAttribute->getActor')->andReturn($this->actor); + $this->actor->shouldReceive('SOME PERMISSION')->andReturn(true/false); +``` + +NOTE: If you find your extension needs _lots and lots_ of mocks, or mocks that feel unrelated, it might be an opportunity to simplify your code, perhaps moving key logic into their own smaller functions (that dont require mocks). + +## Frontend Tests + +### Configuración + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update frontend testing infrastructure to your code: + +```bash +$ flarum-cli infra frontendTesting +``` + +::: + +First, you need to install the Jest config dev dependency: + +```bash +$ yarn add --dev @flarum/jest-config +``` + +Then, add the following to your `package.json`: + +```json +{ + "type": "module", + "scripts": { + ..., + "test": "yarn node --experimental-vm-modules $(yarn bin jest)" + } +} +``` + +Rename `webpack.config.js` to `webpack.config.cjs`. This is necessary because Jest doesn't support ESM yet. + +Create a `jest.config.cjs` file in the root of your extension: + +```js +module.exports = require('@flarum/jest-config')(); +``` + +If you are using TypeScript, create tsconfig.test.json with the following content: + +```json +{ + "extends": "./tsconfig.json", + "include": ["tests/**/*"], + "files": ["../../../node_modules/@flarum/jest-config/shims.d.ts"] +} +``` + +Then, you will need to set up a file structure for tests: + +``` +js +├── dist +├── src +├── tests +│ ├── unit +│ │ └── functionTest.test.js +│ ├── integration +│ │ └── componentTest.test.js +├── package.json +├── tsconfig.json +├── tsconfig.test.json +├── jest.config.cjs +└── webpack.config.cjs +``` + +#### Flujo de trabajo de pruebas en Github + +To run tests on every commit and pull request, check out the [GitHub Actions](github-actions.md) page. + +### Using Unit Tests + +Like any other JS project, you can use Jest to write unit tests for your frontend code. Checkout the [Jest docs](https://jestjs.io/docs/using-matchers) for more information on how to write tests. + +Here's a simple example of a unit test fo core's `abbreviateNumber` function: + +```ts +import abbreviateNumber from '../../../../src/common/utils/abbreviateNumber'; + +test('does not change small numbers', () => { + expect(abbreviateNumber(1)).toBe('1'); +}); + +test('abbreviates large numbers', () => { + expect(abbreviateNumber(1000000)).toBe('1M'); + expect(abbreviateNumber(100500)).toBe('100.5K'); +}); + +test('abbreviates large numbers with decimal places', () => { + expect(abbreviateNumber(100500)).toBe('100.5K'); + expect(abbreviateNumber(13234)).toBe('13.2K'); +}); +``` + +### Uso de las pruebas de integración + +Integration tests are used to test the components of your frontend code and the interaction between different components. For example, you might test that a page component renders the correct content based on certain parameters. + +Here's a simple example of an integration test for core's `Alert` component: + +```ts +import Alert from '../../../../src/common/components/Alert'; +import m from 'mithril'; +import mq from 'mithril-query'; +import { jest } from '@jest/globals'; + +describe('Alert displays as expected', () => { + it('should display alert messages with an icon', () => { + const alert = mq(m(Alert, { type: 'error' }, 'Shoot!')); + expect(alert).toContainRaw('Shoot!'); + expect(alert).toHaveElement('i.icon'); + }); + + it('should display alert messages with a custom icon when using a title', () => { + const alert = mq(Alert, { type: 'error', icon: 'fas fa-users', title: 'Woops..' }); + expect(alert).toContainRaw('Woops..'); + expect(alert).toHaveElement('i.fas.fa-users'); + }); + + it('should display alert messages with a title', () => { + const alert = mq(m(Alert, { type: 'error', title: 'Error Title' }, 'Shoot!')); + expect(alert).toContainRaw('Shoot!'); + expect(alert).toContainRaw('Error Title'); + expect(alert).toHaveElement('.Alert-title'); + }); + + it('should display alert messages with custom controls', () => { + const alert = mq(Alert, { type: 'error', controls: [m('button', { className: 'Button--test' }, 'Click me!')] }); + expect(alert).toHaveElement('button.Button--test'); + }); +}); + +describe('Alert is dismissible', () => { + it('should show dismiss button', function () { + const alert = mq(m(Alert, { dismissible: true }, 'Shoot!')); + expect(alert).toHaveElement('button.Alert-dismiss'); + }); + + it('should call ondismiss when dismiss button is clicked', function () { + const ondismiss = jest.fn(); + const alert = mq(Alert, { dismissible: true, ondismiss }); + alert.click('.Alert-dismiss'); + expect(ondismiss).toHaveBeenCalled(); + }); + + it('should not be dismissible if not chosen', function () { + const alert = mq(Alert, { type: 'error', dismissible: false }); + expect(alert).not.toHaveElement('button.Alert-dismiss'); + }); +}); +``` + +#### Methods + +These are the custom methods that are available for mithril component tests: +* **`toHaveElement(selector)`** - Checks if the component has an element that matches the given selector. +* **`toContainRaw(content)`** - Checks if the component HTML contains the given content. + +To negate any of these methods, simply prefix them with `not.`. For example, `expect(alert).not.toHaveElement('button.Alert-dismiss');`. For more information, check out the [Jest docs](https://jestjs.io/docs/using-matchers). For example you may need to check how to [mock functions](https://jestjs.io/docs/mock-functions), or how to use `beforeEach` and `afterEach` to set up and tear down tests. + + + +## E2E Tests + +Coming Soon! diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/theme.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/theme.md new file mode 100644 index 000000000..197dcee17 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/theme.md @@ -0,0 +1,27 @@ +# Inicio rápido + +Flarum "themes" are just extensions. Typically, you'll want to use the `Frontend` extender to register custom [Less](https://lesscss.org/#overview) and JS. Of course, you can use other extenders too: for example, you might want to support settings to allow configuring your theme. + +You can indicate that your extension is a theme by setting the "extra.flarum-extension.category" key to "theme". Por ejemplo: + +```json +{ + // other fields + "extra": { + "flarum-extension": { + "category": "theme" + } + } + // other fields +} +``` + +All this will do is show your extension in the "theme" section in the admin dashboard extension list. + +## Less Variable Customization + +You can define new Less variables in your extension's Less files. There currently isn't an extender to modify Less variable values in the PHP layer, but this is planned for future releases. + +## Switching Between Themes + +Flarum doesn't currently have a comprehensive system that would support switching between themes. This is planned for future releases. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/translate.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/translate.md new file mode 100644 index 000000000..24ab6380b --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/translate.md @@ -0,0 +1,39 @@ +# Traducción de Flarum + +### LanguagePack + +Como extensor más simple, el extensor [`LanguagePack`](https://github.com/flarum/core/blob/master/src/Extend/LanguagePack.php) le permite definir que su extensión es un paquete de idiomas. + +Este extensor no tiene setters. Todo lo que tienes que hacer es instanciarlo, asegurarte de que tu paquete de idiomas está en la carpeta `locale`, ¡y ya está! + +Aquí hay un ejemplo rápido de [Flarum English](https://github.com/flarum/lang-english/blob/master/extend.php): + +```php +translator->trans('some.translation', ['{username}' => 'Some Username!'])`). +- There's no support for complex applications (nested pluralization, non-number-based selection) +- As a result of the previous point, genderization is impossible. And that's kinda important for a lot of languages. + +### New System + +In v5, Symfony dropped their proprietary `transChoice` system in favor of the more-or-less standard [ICU MessageFormat](https://symfony.com/doc/5.2/translation/message_format.html). This solves pretty much every single one of the aforementioned issues. In this release, Flarum will be fully switching to ICU MessageFormat as well. What does this mean for extensions? + +- `transChoice` should not be used at all; instead, the variable passed for pluralization should be included in the data. +- Keys for backend translations no longer need to be surrounded by curly braces. +- Translations can now use the [`select` and `plural`](https://symfony.com/doc/5.2/translation/message_format.html) formatter syntaxes. For the `plural` formatter, the `offset` parameter and `#` magic variables are supported. +- These `select` and `plural` syntaxes can be nested to arbitrary depth. This is often a bad idea though (beyond, say, 2 levels), as things can get unnecessarily complex. + +No change to translation file naming is necessary (Symfony docs say that an `+intl-icu` suffix is necessary, but Flarum will now interpret all translation files as internationalized). + +#### Future Changes + +In the future, this will serve as a basis for additional features: + +- Translator preprocessors will allow extensions to modify arguments passed to translations. This will enable genderization (extensions could automatically extract a gender field from any objects of type "user" passed in). +- We could support internationalized "magic variables" for numbers: currently, `one` is supported, but others (`few`, `many`, etc) currently aren't. +- We could support ordinal formatting in additional to just plural formatting. + +#### Changes Needed in Extensions + +The `transChoice` methods in the frontend and backend have been removed. The `trans` method should always be used for translating, regardless of pluralization. If a translation requires pluralization, make sure you pass in the controlling variable as one of the arguments. + +In the frontend, code that looked like this: + +```js +app.translator.transChoice('some-translation', guestCount, {host: hostName}); +``` + +should be changed to: + +```js +// This uses ES6 key-property shorthand notation. {guestCount: guestCount} is equivalent to {guestCount} +app.translator.trans('some-translation', {host: hostName, guestCount }); +``` + +Similarly, in the backend, + +```php +$translator->transChoice('some-translation', $guestCount, ['{host}' => $hostName]); +``` + +should be changed to: + +```php +$translator->trans('some-translation', ['host' => $hostName, 'guestCount' => $guestCount]); +``` + +Note that in the backend, translation keys were previously wrapped in curly braces. This is no longer needed. + +#### Changes Needed in Translations + +Translations that aren't using pluralization don't need any changes. + +Pluralized translations should be changed as follows: + +`For {count} minute|For {count} minutes` + +to + +`{count, plural, one {For # minute} other {For # minutes}}` + +Note that in this example, `count` is the variable that controls pluralization. If a different variable were used (such as guestCount in the example above), this would look like: + +`{guestCount, plural, one {For # minute} other {For # minutes}}` + +See [our i18n docs](i18n.md) for more information. + +### Permissions Changes + +For a long time, the `viewDiscussions` and `viewUserList` permissions have been confusing. Despite their names: + +- `viewDiscussions` controls viewing both discussions and users. +- `viewUserList` controls searching users, not viewing user profiles. + +To clear this up, in v1.0, these permissions have been renamed to `viewForum` and `searchUsers` respectively. A migration in core will automatically adjust all permissions in the database to use the new naming. However, any extension code using the old name must switch to the new ones immediately to avoid security issues. To help the transfer, a warning will be thrown if the old permissions are referenced. + +We have also slightly improved tag scoping for permissions. Currently, permissions can be applied to tags if: + +- The permission is `viewForum` +- The permission is `startDiscussion` +- The permission starts with `discussion.` + +However, this doesn't work for namespaced permissions (`flarum-acme.discussion.bookmark`), or permissions that don't really have anything to do with discussions, but should still be scoped (e.g. `viewTag`). To counter this, a `tagScoped` attribute can be used on the object passed to [`registerPermission`](admin.md) to explicitly indicate whether the permission should be tag scopable. If this attribute is not provided, the current rules will be used to determine whether the permission should be tag scopable. + +## Frontend + +### Tooltip Changes + +The `flarum/common/components/Tooltip` component has been introduced as a simpler and less framework-dependent way to add tooltips. If your code is creating tooltips directly (e.g. via `$.tooltip()` in `oncreate` methods), you should wrap your components in the `Tooltip` component instead. Por ejemplo: + +```tsx + + + +``` + +See [the source code](https://github.com/flarum/core/blob/master/js/src/common/components/Tooltip.tsx) for more examples and instructions. + +See [the PR](https://github.com/flarum/core/pull/2843/files) for examples of how to change existing code to use tooltips. + +### PaginatedListState + +The `flarum/common/states/PaginatedListState` state class has been introduced to abstract away most of the logic of `DiscussionListState` and `NotificationListState`. It provides support for loading and displaying paginated lists of JSON:API resources (usually models). In future releases, we will also provide an `PaginatedList` (or `InfiniteScroll`) component that can be used as a base class for these paginated lists. + +Please see [the source code](https://github.com/flarum/core/blob/master/js/src/common/states/PaginatedListState.ts) for a list of methods. + +Note that `flarum/forum/states/DiscussionListState`'s `empty` and `hasDiscussions` methods have been removed, and replaced with `isEmpty` and `hasItems` respectively. Este es un cambio de última hora. + +### New Loading Spinner + +The old `spin.js` based loading indicator has been replaced with a CSS-based solution. For the most part, no changes should be needed in extensions, but in some cases, you might need to update your spinner. This change also makes it easier to customize the spinner. + +See [this discussion](https://discuss.flarum.org/d/26994-beta16-using-the-new-loading-spinner) for more information. + +### classList util + +Ever wrote messy code trying to put together a list of classes for some component? Well, no longer! The [clsx library](https://www.npmjs.com/package/clsx) is now available as the `flarum/common/utils/classList` util. + +### User List + +An extensible user list has been added to the admin dashboard. In future releases, we hope to extract a generic model table component that can be used to list any model in the admin dashboard. + +See [the source code](https://github.com/flarum/core/blob/master/js/src/admin/components/UserListPage.tsx#L41) for a list of methods to extend, and examples of how columns should look like (can be added by extending the `columns` method and adding items to the [ItemList](frontend.md)). + +### Varios + +- Components should now call `super` for ALL Mithril lifecycle methods they define. Before, this was only needed for `oninit`, `onbeforeupdate`, and `oncreate`. Now, it is also needed in `onupdate`, `onbeforeremove`, and `onremove`. See [this GitHub issue](https://github.com/flarum/core/issues/2446) for information on why this change was made. +- The `flarum/common/utils/insertText` and `flarum/common/utils/styleSelectedText` utils have been moved to core from `flarum/markdown`. See `flarum/markdown` for an example of usage. +- The `extend` and `override` utils can now modify several methods at once by passing in an array of method names instead of a single method name string as the second argument. This is useful for extending the `oncreate` and `onupdate` methods at once. +- The `EditUserModal` component is no longer available through the `flarum/forum` namespace, it has been moved to `flarum/common`. Imports should be adjusted. +- The `Model` and `Route` JS extenders have been removed for now. There aren't currently used in any extensions that we know of. We will be reintroducing JS extenders during v1.x releases. +- The `Search` component can now be used with the `SearchState` state class. Previously, `SearchState` was missing the `getInitialSearch` method expected by the `Search` component. + +## Backend + +### Filesystem Extenders + +In this release, we refactored our use of the filesystem to more consistently use [Laravel's filesystem API](https://laravel.com/docs/8.x/filesystem). Extensions can now declare new disks, more easily use core's `flarum-assets` and `flarum-avatars` disks, and create their own storage drivers, enabling CDN and cloud storage support. + +### Compat and Closure Extenders + +In early Flarum versions, the `extend.php` file allowed arbitrary functions that allowed execution of arbitrary code one extension boot. Por ejemplo: + +```php +return [ + // other extenders + function (Dispatcher $events) { + $events->subscribe(Listener\FilterDiscussionListByTags::class); + $events->subscribe(Listener\FilterPostsQueryByTag::class); + $events->subscribe(Listener\UpdateTagMetadata::class); + } +]; +``` + +This approach was difficult to maintain and provide a well-tested public API for, frequently resolved classes early (breaking all sorts of things), and was not very descriptive. With the extender API completed in beta 16, this approach is no longer necessary. Support for these closures has been removed in this stable version. + +One type of functionality for which the extender replacement isn't obvious is container bindings ([e.g. flarum/pusher](https://github.com/flarum/pusher/blob/v0.1.0-beta.14/extend.php#L33-L49)). This can be done with via the service provider extender (e.g. [a newer version of flarum/pusher](https://github.com/flarum/pusher/blob/master/extend.php#L40-L41)). + +If you are unsure about which extenders should be used to replace your use of callbacks in `extend.php`, or are not sure that such an extender exists, please comment so below or reach out! We're in the final stages of finishing up the extender API, so now is the time to comment. + +### Scheduled Commands + +The [fof/console](https://github.com/FriendsOfFlarum/console) library has been a popular way to schedule commands (e.g. for publishing scheduled posts, running DB-heavy operations, etc) for several release. In Flarum 1.0, this functionality has been brought into core's `Console` extender. See our [console extension documentation](console.md) for more information on how to create schedule commands, and our [console user documentation](../console.md) for more information on how to run scheduled commands. + +### Eager Loading Extender + +As part of solving [N+1 Query issues](https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/) in some [Flarum API endpoints](https://github.com/flarum/core/issues/2637), we have introduced a `load` method on the `ApiController` extender that allows you to indicate relations that should be eager loaded. + +This should be done if you know a relation will always be included, or will always be referenced by controller / permission logic. For example, we will always need the tags of a discussion to check what permissions a user has on that discussion, so we should eager load the discussion's `tags` relationship. Por ejemplo: + +```php +return [ + // other extenders + (new Extend\ApiController(FlarumController\ListDiscussionsController::class)) + ->addInclude(['tags', 'tags.state', 'tags.parent']) + ->load('tags'), +]; +``` + +### RequestUtil + +The `Flarum\Http\RequestUtil`'s `getActor` and `withActor` should be used for getting/setting the actor (user) on requests. `$request->getAttribute('actor')` and `$request->withAttribute('actor')` are deprecated, and will be removed in v2.0. + +### Varios + +- The `Formatter` extender now has an `unparse` method that allows modifying XML before unparsing content. +- All route names must now be unique. In beta 16, uniqueness was enforced per-method; now, it is mandatory for all routes. +- API requests sent through `Flarum\Api\Client` now run through middleware, including `ThrottleApi`. This means that it is now possible to throttle login/registration calls. +- In beta 16, registering custom [searchers](search.md) was broken. It has been fixed in stable. +- The `post_likes` table in the [flarum/likes](https://github.com/flarum/likes) extension now logs the timestamp when likes were created. This isn't used in the extension, but could be used in other extensions for analytics. +- The `help` attribute of [admin settings](admin.md) no longer disappears on click. +- The `generate:migration` console command has been removed. The [Flarum CLI](https://discuss.flarum.org/d/26525-rfc-flarum-cli-alpha) should be used instead. +- The `GambitManager` util class is now considered internal API, and should not be used directly by extensions. +- The `session` attribute is no longer available on the `User` class. This caused issues with queue drivers, and was not conceptually correct (a user can have multiple sessions). The current session is still available via the `$request` instance. +- The `app`, `base_path`, `public_path`, `storage_path`, and `event` global helpers have been restored, but deprecated perpetually. These exist in case Laravel packages need them; they **should not** be used directly by Flarum extension code. The `flarum/laravel-helpers` package has been abandoned. +- The following deprecated features from beta 16 have been removed: + - The `TextEditor`, `TextEditorButton`, and `SuperTextarea` components are no longer exported through the `flarum/forum` namespace, but through `flarum/common` (with the exception of `SuperTextarea`, which has been replaced with `flarum/common/utils/BasicEditorDriver`). + - Support for `Symfony\Component\Translation\TranslatorInterface` has been removed, `Symfony\Contracts\Translation\TranslatorInterface` should be used instead. + - All backwards compatibility layers for the [beta 16 access token refactors](update-b16.md#access-token-and-authentication-changes) have been removed + - The `GetModelIsPrivate` event has been removed. The `ModelPrivate` extender should be used instead. + - The `Searching` (for both `User` and `Discussion` models), `ConfigureAbstractGambits`, `ConfigureDiscussionGambits`, and `ConfigureUserGambits` events have been removed. The `SimpleFlarumSearch` extender should be used instead. + - The `ConfigurePostsQuery` event has been removed. The `Filter` extender should be used instead. + - The `ApiSerializer` extender's `mutate` method has been removed. The same class's `attributes` method should be used instead. + - The `SearchCriteria` and `SearchResults` util classes have been removed. `Flarum\Query\QueryCriteria` and `Flarum\Query\QueryResults` should be used instead. + - The `pattern` property of `AbstractRegexGambit` has been removed; the `getGambitPattern` method is now a required abstract method. + - The `AbstractSearch` util class has been removed. `Flarum\Search\SearchState` and `Flarum\Filter\FilterState` should be used instead. + - The `CheckingPassword` event has been removed, the `Auth` extender should be used instead. + +## Tags Extension Changes + +As mentioned above, [tag scopable permissions](#permissions-changes) can now be explicitly declared. + +We've also made several big refactors to significantly improve tags performance. + +Firstly, the [Tag](https://github.com/flarum/tags/blob/d093ca777ba81f826157522c96680717d3a90e24/src/Tag.php#L38-L38) model's static `getIdsWhereCan` and `getIdsWhereCannot` methods have been removed. These methods scaled horribly on forums with many tags, sometimes adding several seconds to response time. + +These methods have been replaced with a `whereHasPermission` [Eloquent dynamic scope](https://laravel.com/docs/8.x/eloquent#dynamic-scopes) that returns a query. Por ejemplo: + +`Tag::whereHasPermission($actor, 'viewDiscussions)`. + +That query can then be used in other DB queries, or further constricted to retrieve individual tags. + +Secondly, we no longer load in all tags as part of the initial payload. The initial payload contains all top-level primary tags, and the top 3 secondary tags. Other tags are loaded in as needed. Future releases will paginate secondary tags. This should enable forums to have thousands of secondary tags without significant performance impacts. These changes mean that extensions should not assume that all tags are available in the model store. + +## Testing Library Changes + +- Bundled extensions will not be automatically enabled; all enabled extensions must be specified in that test case. +- `setting` and `config` methods have been added that allow configuring settings and config.php values before the tested application boots. See [the testing docs](testing.md) for more information. +- The `php flarum test:setup` command will now drop the existing test DB tables before creating the database. This means that you can run `php flarum test:setup` to ensure a clean database without needing to go into the database and drop tables manually. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md new file mode 100644 index 000000000..ed17364ed --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md @@ -0,0 +1,139 @@ +# Updating For 1.x + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## 1.7 + +### Frontend + +- Frontend extenders similar to the backend have been added, we highly recommend using them instead of the old method (https://docs.flarum.org/extend/models#adding-new-models-1), (https://docs.flarum.org/extend/routes#frontend-routes). +- There is a new tag selection component (https://github.com/flarum/framework/blob/360a2ba1d886df3fc6d326be932c5431ee9df8cf/extensions/tags/js/src/common/components/TagSelectionModal.tsx). + +### Backend + +- Support for php 8.2, deprecations are still thrown by some packages, the testing workflow has been updated to ignore deprecations on 8.2 +- The `/api` endpoint now contains the actor as an included relationship. +- The `Model::dateAttribute($attribute)` extender is deprecated, use `Model::cast($attribute, 'datetime')` instead. + +### Tooling + +- New `phpstan` package to run static code analysis on your extensions for code safety (https://docs.flarum.org/extend/static-code-analysis). +- New `jest-config` package to run frontend unit and component tests (https://docs.flarum.org/extend/testing). + +## 1.6 Changes + +### Backend + +- Added customizable session drivers through the `Session` extender. + +## 1.5 Changes + +### Frontend + +- More portions of the frontend are now written in TypeScript, providing a better extension development experience. +- Modals can be used in stacks, allowing for multiple modals to be open at once. This is useful for modals that open other modals: `app.modal.show(ModalComponent, { attrs }, true)`. + +### Backend + +- There is a new `createTableIfNotExists` migration helper, which can be used to create tables only if they don't already exist. + +## 1.4 Changes + +No developer-facing changes were made in Flarum v1.4. + +## 1.3 Changes + +Flarum v1.3 included mostly QoL improvements. Below are listed note worthy changes for extension developers: + +### Frontend + +- More portions of the frontend are now written in TypeScript, providing a better extension development experience. +- Frontend errors will no longer cause the forum to crash into a NoJs page. The extension will fail to execute its frontend code (initializer) and display an error to the admin through an alert, and to all users through the console. The frontend will continue to execute without the extension's frontend changes. +- The markdown toolbar can now be used on the admin side. + +### Backend + +- Calculation of the `number` attribute on `posts` has changed and no longer relies on the discussion model's `post_number_index` attribute which is now deprecated and will be removed in 2.0 +- Extension event listeners are now added after core even listeners, this should generally cause no changes in behavior. + +### Tooling + +- The backend tests workflow now automatically fails tests if there are any PHP warnings and notices. + +## 1.2 Changes + +Flarum v1.2 included quite a few bugfixes, internal refactors, and new features. The following recaps the most important changes for extension developers: + +### Frontend + +- Flarum core now passes TypeScript type checking (on the portion written in TypeScript). Additionally, major portions of the frontend (models, the application instance, and others) are now written in TypeScript. These changes should make it much easier and more fruitful to write extensions in TypeScript. +- Instead of directly using Less variables in CSS code, core now uses CSS variables. For the most part, we've just created CSS variables and set their values to the Less variables. This should make theming and customizing CSS a lot easier. https://github.com/flarum/core/pull/3146. +- Dropdowns can now be lazy-drawn to improve performance. You can do this by setting the lazy draw attr to "true". https://github.com/flarum/core/pull/2925. +- [Textarea-type settings](https://github.com/flarum/core/pull/3141) are now supported through the `app.extensionData.registerSetting` util. +- You can now use Webpack 5 to bundle your extension's code. This will offer minor bundle size improvements. +- A new `flarum/common/components/ColorPreviewInput` component [has been added](https://github.com/flarum/core/pull/3140). It can be used directly, or through the `color-preview` type when registered via `app.extensionData.registerSetting`. +- Extensions can now [modify the minimum search length](https://github.com/flarum/core/pull/3130) of the `Search` component. +- The following components are now extensible: + - The "colors" part of the Appearance page in the admin dashboard: https://github.com/flarum/core/pull/3186 + - The `StatusWidget` dropdown in the admin dashboard: https://github.com/flarum/core/pull/3189 + - `primaryControls` in the notification list: https://github.com/flarum/core/pull/3204 +- Extensions now have finer control over positioning when adding elements to the DiscussionPage sidebar items: https://github.com/flarum/core/pull/3165 +- + +### Backend + +- An [extender for settings defaults](https://github.com/flarum/core/pull/3127) has been added. This should be used instead of the `addSettings` migration helper, which has been deprecated. +- You can now [generate Less variables from setting values](https://github.com/flarum/core/pull/3011) via the `Settings` extender. +- Extensions can now [override/supplement blade template namespaces](https://github.com/flarum/core/pull/3167) through the `View` extender, meaning custom blade templates can be used instead of the default ones added by core or extensions. +- You can now define [custom Less functions through PHP](https://github.com/flarum/core/pull/3190), allowing you to use some backend logic in your Less theming. +- Extensions can now create [custom page title drivers](https://github.com/flarum/core/pull/3109/files) for titles in server-returned HTML. +- Custom logic can now be used when [deciding which relations to eager-load](https://github.com/flarum/core/pull/3116). +- Events [are now dispatched](https://github.com/flarum/core/pull/3203) for the `Notification\Read` and `Notification\ReadAll` events. +- An `ImageManager` instance is now [bound into the container](https://github.com/flarum/core/pull/3195), and can be configured to use either the `gd` or `imagick` backing drivers via the `"intervention.driver"` key in `config.php`. +- User IP addresses are now passed to the [API Client](https://github.com/flarum/core/pull/3124). +- A custom revision versioner implentation [can be set via container bindings](https://github.com/flarum/core/pull/3183) to customize how asset versions are named. +- A SlugManager instance [is now available](https://github.com/flarum/core/pull/3194) in blade templates via the `slugManager` variable. + +### Misc + +- Translations now support the `zero`, `one`, `two`, `few`, and `many` localized plural rules for `plural` ICU MessageFormat translations. This was done through the [`Intl.PluralRules` helper](https://github.com/flarum/core/issues/3072). +- Translations are now used for page titles, so that the format can be customized via language packs or [Linguist](https://discuss.flarum.org/d/7026-linguist-customize-translations-with-ease): https://github.com/flarum/core/pull/3077, https://github.com/flarum/core/pull/3228 +- API endpoints for retrieving single groups, as well as support for filtering groups on the plural get endpoint, [have been added](https://github.com/flarum/core/pull/3084). + + +### Tooling + + +- The `flarum-cli infra` command can now be used to update or enable various infrastructure features. You can now add the following to your extension in just one command: + - TypeScript + - Prettier for JS/TS formatting + - Backend testing with PHPUnit + - Code formatting with StyleCI + - EditorConfig support + - GitHub actions for automating testing, linting, type checking, and building. +- You can also exclude any files from these updates by adding their relative path to the "extra.flarum-cli" key's array in your extension's `composer.json` file. For example, if you wanted to exclude your tsconfig file from any updates by the infra system, the "extra.flarum-cli" key's value should be `["js/tsconfig.json"]`. +- The `flarum-cli audit infra` can be used to check that all infra modules your extension uses are up to date. The `--fix` flag can be used to automatically fix any issues, which has essentially the same effect as running `flarum-cli infra` for each outdated module. +- All `flarum-cli` commands can now be run with a `--no-interaction` flag to prevent prompts. Defaults will be used when possible, and errors will be thrown if a prompt is needed and there is no default. +- Frontend GH actions now support type-checking, as well as type coverage reports. + +## 1.1 Changes + +Flarum version 1.1 mostly focuses on bugfixes and quality-of-life improvements following our stable release earlier this year. These are mainly user-facing and internal infrastructure changes, so extensions are not significantly affected. + +### Frontend + +- Flarum now has an organization-wide prettier config package under [`@flarum/prettier-config`](https://github.com/flarum/prettier-config). +- Most custom (setting or data based) coloring in core is now done via [CSS custom properties](https://github.com/flarum/core/pull/3001). +- Typehinting for Flarum's globals are now [supported in extensions](https://github.com/flarum/core/pull/2992). +- You can now pass extra attrs to the `Select` component, and they will be [passed through to the DOM](https://github.com/flarum/core/pull/2959). +- The `DiscussionPage` component is now organized [as an item list](https://github.com/flarum/core/pull/3004), so it's easier for extensions to change its content. +- Extensions [can now edit](https://github.com/flarum/core/pull/2935) the `page` parameter of `PaginatedListState`. + +### Backend + +- Flarum now comes with a [Preload extender](https://github.com/flarum/core/pull/3057) for preloading any custom frontend assets. +- A new [Theme](https://github.com/flarum/core/pull/3008) extender now allows overriding Less files and internal imports. This allows themes to more easily completely replace Less modules. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md new file mode 100644 index 000000000..aaa98a2a5 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md @@ -0,0 +1,53 @@ +# Updating For Beta 10 + +Beta 10 further solidifies the core architecture, offering new extenders as a stable, use-case-driven API for extending Flarum's core. A few small changes may necessitate updates to your extensions to make them compatible with Beta 10. These are detailed below. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Breaking Changes + +- The `Flarum\Event\GetDisplayName` class has been moved to `Flarum\User\Event\GetDisplayName`. +- The `Flarum\Http\Exception\ForbiddenException` has been removed. Use `Flarum\User\Exception\PermissionDeniedException` instead. +- The `assertGuest()` method of the `Flarum\User\AssertPermissionTrait` has been removed without replacement. +- Old error handling middleware and exception handler classes were removed (see "New Features" for more details): + - `Flarum\Api\Middleware\HandleErrors` + - `Flarum\Http\Middleware\HandleErrorsWithView` + - `Flarum\Http\Middleware\HandleErrorsWithWhoops` + - `Flarum\Api\ErrorHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + - `Flarum\Api\ExceptionHandler\FloodingExceptionHandler` + - `Flarum\Api\ExceptionHandler\IlluminateValidationExceptionHandler` + - `Flarum\Api\ExceptionHandler\InvalidAccessTokenExceptionHandler` + - `Flarum\Api\ExceptionHandler\InvalidConfirmationTokenExceptionHandler` + - `Flarum\Api\ExceptionHandler\MethodNotAllowedExceptionHandler` + - `Flarum\Api\ExceptionHandler\ModelNotFoundExceptionHandler` + - `Flarum\Api\ExceptionHandler\PermissionDeniedExceptionHandler` + - `Flarum\Api\ExceptionHandler\RouteNotFoundExceptionHandler` + - `Flarum\Api\ExceptionHandler\TokenMismatchExceptionHandler` + - `Flarum\Api\ExceptionHandler\ValidationExceptionHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + +## Recommendations + +- We tweaked the [recommended flarum/core version constraints for extensions](start.md#composer-json). We now recommend you mark your extension as compatible with the current and the upcoming beta release. (For beta.10, that would be any beta.10.x and beta.11.x version.) The core team will strive to make this work well by deprecating features before removing them. More details on this change in [this pull request](https://github.com/flarum/docs/pull/75). + +## New Features + +- New, extensible **error handling** stack in the `Flarum\Foundation\ErrorHandling` namespace: The `Registry` maps exceptions to "types" and HTTP status codes, `HttpFormatter` instances turn them into HTTP responses. Finally, `Reporter` instances are notified about unknown exceptions. + - You can build custom exception classes that will abort the current request (or console command). If they have semantic meaning to your application, they should implement the `Flarum\Foundation\KnownError` interface, which exposes a "type" that is used to render pretty error pages or dedicated error messages. + - More consistent use of HTTP 401 and 403 status codes. HTTP 401 should be used when logging in (i.e. authenticating) could make a difference; HTTP 403 is reserved for requests that fail because the already authenticated user is lacking permissions to do something. + - The `assertRegistered()` and `assertPermission()` methods of the `Flarum\User\AssertPermissionTrait` trait have been changed to match above semantics. See [this pull request](https://github.com/flarum/core/pull/1854) for more details. + - Error views are now determined based on error "type", not on status code (see [bdac88b](https://github.com/flarum/core/commit/bdac88b5733643b9c5dabae9e09a64d9f6e41d58)) +- **Queue support**: This release incorporates Laravel's illuminate/queue package, which allows offloading long-running tasks (such as email sending or regular cleanup jobs) onto a dedicated worker process. These changes are mostly under the hood, the next release(s) will start using the queue system for sending emails. By default, Flarum will use the "sync" queue driver, which executes queued tasks immediately. This is far from ideal and mostly guarantees a hassle-free setups. Production-grade Flarum installs are expected to upgrade to a more full-featured queue adapter. +- The `Flarum\Extend\LanguagePack` now accepts an optional path in its constructor. That way, language packs can store their locales in a different directory if they want to. +- The `formatContent()` method of `Flarum\Post\CommentPost` can now be called without an HTTP request instance, e.g. when rendering a post in an email template. + +## Deprecations + +- **Reminder**: In previous versions of Flarum, an extensions' main file was named `bootstrap.php`. This name will no longer be supported in the stable 0.1 release. Make sure your extension uses the name `extend.php`. +- Laravel's global string and array helpers (e.g. `str_contains()` and `array_only()`) are deprecated in favor of their class based alternatives (`Illuminate\Support\Str::contains()` and `Illuminate\Support\Arr::only()`). See the [announcement](https://laravel-news.com/laravel-5-8-deprecates-string-and-array-helpers) and [pull request](https://github.com/laravel/framework/pull/26898) for more information. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md new file mode 100644 index 000000000..ce6b1aca2 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md @@ -0,0 +1,34 @@ +# Updating For Beta 12 + +Beta 12 packs several new features for extension developers, but also continues our cleanup efforts which results in a few changes, so please read this guide carefully to find out whether your extensions are affected. We invested extra effort to introduce new functionality in a backward-compatible manner or first deprecate functionality before it will be removed in the next release, in line with our [versioning recommendations](start.md#composer-json). + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Deprecations / Upcoming breaking changes + +- **Reminder**: In previous versions of Flarum, an extensions' main file was named `bootstrap.php`. This name will no longer be supported in the stable 0.1 release. Make sure your extension uses the name `extend.php`. +- PHP 7.1 support will be dropped in beta.13. +- Using library classes from the `Zend` namespace is now deprecated and will be removed in beta.13. Use the `Laminas` namespace instead. See [PR #1963](https://github.com/flarum/core/pull/1963). +- The `Flarum\Util\Str::slug()` method has been deprecated. Use `Illuminate\Support\Str::slug()` instead. +- The `Flarum\Event\ConfigureMiddleware` has been deprecated. We finally have a [proper replacement](middleware.md) - see "New Features" below. Therefore, it will be removed in beta.13. +- If you implement the `Flarum\Mail\DriverInterface`: + - Returning a plain array of field names from the `availableSettings()` method is deprecated, but still supported. It must now return an array of field names mapping to their type. See [the inline documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L25-L32) for more details. + - Implement the `validate()` method that will be required in beta.13. See [its documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L34-L48). + - Implement the `canSend()` method that will be required in beta.13. See [its documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L50-L54). + +## New Features + +- New **PHP extenders**: + - `Flarum\Extend\Middleware` offers methods for adding, removing or replacing middleware in our three middleware stacks (api, forum, admin). We also added [documentation](middleware.md) for this feature. + - `Flarum\Extend\ErrorHandling` lets you configure status codes and other aspects of our error handling stack depending on error types or exception classes. +- **JavaScript**: + - The `flarum/components/Select` component now supports a `disabled` prop. See [PR #1978](https://github.com/flarum/core/pull/1978). + +## Other changes / Recommendations + +- The `TextFormatter` library has been updated to (at least) version 2.3.6. If you are using it (likely through our own `Flarum\Formatter\Formatter` class), we recommend scanning [the library's changelog](https://github.com/s9e/TextFormatter/blob/2.3.6/CHANGELOG.md). +- The JS `slug()` helper from the `flarum/utils/string` module should only be used to *suggest* slugs to users, not enforce them. It does not employ any sophisticated transliteration logic like its PHP counterpart. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md new file mode 100644 index 000000000..1b19a9714 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md @@ -0,0 +1,40 @@ +# Updating For Beta 13 + +Beta 13 ships with several new extenders to simplify building and maintaining extensions. We do our best to create backward compatibility changes. We recommend changing to new Extenders as soon as they are available. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Breaking Changes + +- Dropped support for PHP 7.1. +- Classes from the `Zend` namespace are now removed. Use the `Laminas` namespace instead. See [PR #1963](https://github.com/flarum/core/pull/1963). +- The `Flarum\Util\Str::slug()` method has been removed including the class. Use `Illuminate\Support\Str::slug()` instead. +- The `Flarum\Event\ConfigureMiddleware` has been removed. Use the [proper replacement](middleware.md). +- Several events used in Event Listeners have been removed, use their [replacement extender](start.md#extenders) instead. +- The LanguagePack extender only loads keys from extensions that are enabled. The translations loaded are based on the yaml files matching the [i18n namespace](i18n.md#appendix-a-standard-key-format). +- All notifications are now sent through the queue; without a queue driver they will run as usual. +- The implementation of avatar upload changed, we're [no longer storing files temporarily on disk](https://github.com/flarum/core/pull/2117). +- The SES mail driver [has been removed](https://github.com/flarum/core/pull/2011). +- Mail driver backward compatibility from beta 12 has been removed, use the new Mail extender or implement the [modified interface](https://github.com/flarum/core/blob/master/src/Mail/DriverInterface.php). + +## Recommendations + +- Beta 14 will ship with a rewrite in the frontend (javascript). If you're building for that release, make sure to follow our [progress](https://github.com/flarum/core/pull/2126). + +## New Features + +- A ton of new extenders: + - [Middleware extender](https://github.com/flarum/core/pull/2017) + - [Console extender](https://github.com/flarum/core/pull/2057) + - [CSRF extender](https://github.com/flarum/core/pull/2095) + - [Event extender](https://github.com/flarum/core/pull/2097) + - [Mail extender](https://github.com/flarum/core/pull/2012) + - [Model extender](https://github.com/flarum/core/pull/2100) + +## Deprecations + +- Several events [have been marked deprecated](https://github.com/flarum/core/commit/4efdd2a4f2458c8703aae654f95c6958e3f7b60b) to be removed in beta 14. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md new file mode 100644 index 000000000..e06c15e8f --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md @@ -0,0 +1,757 @@ +# Updating For Beta 14 + +This release brings a large chunk of breaking changes - hopefully the last chunk of this size before our stable release. In order to prepare the codebase for the upcoming stable release, we decided it was time to modernize / upgrade / exchange some of the underlying JavaScript libraries that are used in the frontend. Due to the nature and size of these upgrades, we have to pass on some of the breaking changes to you, our extension developers. + +On the bright side, this overdue upgrade brings us closer to the conventions of best practices of [Mithril.js](https://mithril.js.org/), the mini-framework used for Flarum's UI. Mithril's 2.0 release sports a more consistent component interface, which should be a solid foundation for years to come. Where possible, we replicated old APIs, to ease the upgrade and give you time to do the full transition. Quite a few breaking changes remain, though - read more below. + +:::tip + +If you need help with the upgrade, our friendly community will gladly help you out either [on the forum](https://discuss.flarum.org/t/extensibility) or [in chat](https://flarum.org/chat/). + +::: + +To ease the process, we've clearly separated the changes to the [frontend (JS)](#frontend-javascript) from those in the [backend (PHP)](#backend-php) below. If your extension does not change the UI, consider yourself lucky. :-) + +A [summary of the frontend changes](#required-frontend-changes-recap) is available towards the end of this guide. + +## Frontend (JavaScript) + +### Mithril 2.0: Concepts + +Most breaking changes required by beta 14 are prompted by changes in Mithril 2. [Mithril's upgrade guide](https://mithril.js.org/migration-v02x.html) is an extremely useful resource, and should be consulted for more detailed information. A few key changes are explained below: + +#### props -> attrs; initProps -> initAttrs + +Props passed into component are now referred to as `attrs`, and can be accessed via `this.attrs` where you would prior use `this.props`. This was done to be closer to Mithril's preferred terminology. We have provided a temporary backwards compatibility layer for `this.props`, but recommend using `this.attrs`. + +Accordingly, `initProps` has been replaced with `initAttrs`, with a similar BC layer. + +#### m.prop -> `flarum/utils/Stream` + +Mithril streams, which were available via `m.prop` in Mithril 0.2, are now available via `flarum/utils/Stream`. `m.prop` will still work for now due to a temporary BC layer. + +#### m.withAttr -> withAttr + +The `m.withAttr` util has been removed from Mithril. We have provided `flarum/utils/withAttr`, which does the same thing. A temporary BC layer has been added for `m.withAttr`. + +#### Lifecycle Hooks + +In mithril 0.2, we had 2 "lifecycle hooks": + +`init`, an unofficial hook which ran when the component instance was initialized. + +`config`, which ran when components were created, and on every redraw. + + +Mithril 2 has the following hooks; each of which take `vnode` as an argument: + +- `oninit` +- `oncreate` +- `onbeforeupdate` +- `onupdate` +- `onbeforeremove` +- `onremove` + +Please note that if your component is extending Flarum's helper `Component` class, you must call `super.METHOD(vnode)` if using `oninit`, `oncreate`, and `onbeforeupdate`. + +More information about what each of these do can be found [in Mithril's documentation](https://mithril.js.org/lifecycle-methods.html). + +A trivial example of how the old methods map to the new is: + +```js +class OldMithrilComponent extends Component { + init() { + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + config(element, isInitialized) { + console.log('Code to run on every redraw AND when the element is first attached'); + + if (isInitialized) return; + + console.log('Code to execute only once when components are first created and attached to the DOM'); + + context.onunload = () => { + console.log('Code to run when the component is removed from the DOM'); + } + } + + view() { + // In mithril 0, you could skip redrawing a component (or part of a component) by returning a subtree retain directive. + // See https://mithril.js.org/archive/v0.2.5/mithril.render.html#subtree-directives + // dontRedraw is a substitute for logic; usually, this is used together with SubtreeRetainer. + if (dontRedraw()) return { subtree: 'retain' }; + + return

Hello World!

; + } +} + +class NewMithrilComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + oncreate(vnode) { + super.oncreate(vnode); + + console.log('Code to run when components are first created and attached to the DOM'); + } + + onbeforeupdate(vnode, oldVnode) { + super.onbeforeupdate(vnode); + + console.log('Code to run BEFORE diffing / redrawing components on every redraw'); + + // In mithril 2, if we want to skip diffing / redrawing a component, we return "false" in its onbeforeupdate lifecycle hook. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeupdate + // This is also typically used with SubtreeRetainer. + if (dontRedraw()) return false; + } + + onupdate(vnode) { + // Unlike config, this does NOT run when components are first attached. + // Some code might need to be replicated between oncreate and onupdate. + console.log('Code to run on every redraw AFTER the DOM is updated.'); + } + + onbeforeremove(vnode) { + // This is run before components are removed from the DOM. + // If a promise is returned, the DOM element will only be removed when the + // promise completes. It is only called on the top-level component that has + // been removed. It has no equivalent in Mithril 0.2. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeremove + return Promise.resolve(); + } + + onremove(vnode) { + console.log('Code to run when the component is removed from the DOM'); + } +} +``` + +#### Children vs Text Nodes + +In Mithril 0.2, every child of a vnode is another vnode, stored in `vnode.children`. For Mithril 2, as a performance optimization, vnodes with a single text child now store that text directly in `vnode.text`. For developers, that means that `vnode.children` might not always contain the results needed. Luckily, text being stored in `vnode.text` vs `vnode.children` will be the same each time for a given component, but developers should be aware that at times, they might need to use `vnode.text` and not `vnode.children`. + +Please see [the mithril documentation](https://mithril.js.org/vnodes.html#structure) for more information on vnode structure. + +#### Routing API + +Mithril 2 introduces a few changes in the routing API. Most of these are quite simple: + +- `m.route()` to get the current route has been replaced by `m.route.get()` +- `m.route(NEW_ROUTE)` to set a new route has been replaced by `m.route.set(NEW_ROUTE)` +- When registering new routes, a component class should be provided, not a component instance. + +Por ejemplo: + +```js +// Mithril 0.2 +app.routes.new_page = { path: '/new', component: NewPage.component() } + +// Mithril 2.0 +app.routes.new_page = { path: '/new', component: NewPage } +``` + +Additionally, the preferred way of defining an internal (doesn't refresh the page when clicked) link has been changed. The `Link` component should be used instead. + +```js +// Mithril 0.2 +
Link Content + +// Mithril 2 +import Link from 'flarum/components/Link'; + +Link Content +``` + +You can also use `Link` to define external links, which will just render as plain `Children` html links. + +For a full list of routing-related changes, please see [the mithril documentation](https://mithril.js.org/migration-v02x.html). + +#### Redraw API + +Mithril 2 introduces a few changes in the redraw API. Most of these are quite simple: + +- Instead of `m.redraw(true)` for synchronous redraws, use `m.redraw.sync()` +- Instead of `m.lazyRedraw()`, use `m.redraw()` + +Remember that Mithril automatically triggers a redraw after DOM event handlers. The API for preventing a redraw has also changed: + +```js +// Mithril 0.2 + + +// Mithril 2 + +``` + +#### AJAX + +The `data` parameter of `m.request({...})` has been split up into `body` and `params`. + +For examples and other AJAX changes, see [the mithril documentation](https://mithril.js.org/migration-v02x.html#mrequest). + +#### Promises + +`m.deferred` has been removed, native promises should be used instead. Por ejemplo: + +```js +// Mithril 0.2 +const deferred = m.deferred(); + +app.store.find('posts').then(result => deferred.resolve(result)); + +return deferred.promise; + +// Mithril 2 +return app.store.find('posts'); +``` + +#### Component instances should not be stored + +Due to optimizations in Mithril's redrawing algorithms, [component instances should not be stored](https://mithril.js.org/components.html#define-components-statically,-call-them-dynamically). + +So whereas before, you might have done something like: + +```js +class ChildComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return

{this.counter}

; + } +} +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.child = new ChildComponent(); + } + + view() { + return ( +
+ + {this.child.render()} +
+ ) + } +} +``` + +That will no longer work. In fact; the Component class no longer has a render method. + +Instead, any data needed by a child component that is modified by a parent component should be passed in as an attr. Por ejemplo: + +```js +class ChildComponent extends Component { + view() { + return

{this.attrs.counter}

; + } +} + +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return ( +
+ + +
+ ) + } +} +``` + +For more complex components, this might require some reorganization of code. For instance, let's say you have data that can be modified by several unrelated components. In this case, it might be preferable to create a POJO "state instance' for this data. These states are similar to "service" singletons used in Angular and Ember. Por ejemplo: + +```js +class Counter { + constructor() { + this._counter = 0; + } + + increaseCounter() { + this._counter += 1; + } + + getCount() { + return this._counter; + } +} + +app.counter = new Counter(); + +extend(HeaderSecondary.prototype, 'items', function(items) { + items.add('counterDisplay', +
+

Counter: {app.counter.getCount()}

+
+ ); +}) + +extend(HeaderPrimary.prototype, 'items', function(items) { + items.add('counterButton', +
+ +
+ ); +}) +``` + +This "state pattern" can be found throughout core. Some non-trivial examples are: + +- PageState +- SearchState and GlobalSearchState +- NotificationListState +- DiscussionListState + +### Changes in Core + +#### Modales + +Previously, modals could be opened by providing a `Modal` component instance: + +```js +app.modal.show(new LoginModal(identification: 'prefilledUsername')); +``` + +Since we don't store component instances anymore, we pass in the component class and any attrs separately. + +```js +app.modal.show(LoginModal, {identification: 'prefilledUsername'}); +``` + +The `show` and `close` methods are still available through `app.modal`, but `app.modal` now points to an instance of `ModalManagerState`, not of the `ModalManager` component. Any modifications by extensions should accordingly be done to `ModalManagerState`. + +#### Alertas + +Previously, alerts could be opened by providing an `Alert` component instance: + +```js +app.alerts.show(new Alert(type: 'success', children: 'Hello, this is a success alert!')); +``` + +Since we don't store component instances anymore, we pass in a component class, attrs, children separately. The `show` method has 3 overloads: + +```js +app.alerts.show('Hello, this is a success alert!'); +app.alerts.show({type: 'success'}, 'Hello, this is a success alert!'); +app.alerts.show(Alert, {type: 'success'}, 'Hello, this is a success alert!'); +``` + +Additionally, the `show` method now returns a unique key, which can then be passed into the `dismiss` method to dismiss that particular alert. This replaces the old method of passing the alert instance itself to `dismiss`. + +The `show`, `dismiss`, and `clear` methods are still available through `app.alerts`, but `app.alerts` now points to an instance of `AlertManagerState`, not of the `AlertManager` component. Any modifications by extensions should accordingly be done to `AlertManagerState`. + +#### Composer + +Since we don't store a component instances anymore, a number of util methods from `Composer`, `ComposerBody` (and it's subclasses), and `TextEditor` have been moved onto `ComposerState`. + +For `forum/components/Composer`, `isFullScreen`, `load`, `clear`, `show`, `hide`, `close`, `minimize`, `fullScreen`, and `exitFullScreen` have been moved to `forum/states/ComposerState`. They all remain accessible via `app.composer.METHOD` + +A `bodyMatches` method has been added to `forum/states/ComposerState`, letting you check whether a certain subclass of `ComposerBody` is currently open. + +Various input fields are now stored as [Mithril Streams](https://mithril.js.org/stream.html) in `app.composer.fields`. For instance, to get the current composer content, you could use `app.composer.fields.content()`. Previously, it was available on `app.composer.component.content()`. **This is a convention that `ComposerBody` subclasses that add inputs should follow.** + +`app.composer.component` is no longer available. + +- Instead of `app.composer.component instanceof X`, use `app.composer.bodyMatches(X)`. +- Instead of `app.composer.component.props`, use `app.composer.body.attrs`. +- Instead of `app.composer.component.editor`, use `app.composer.editor`. + +For `forum/components/TextEditor`, the `setValue`, `moveCursorTo`, `getSelectionRange`, `insertAtCursor`, `insertAt`, `insertBetween`, `replaceBeforeCursor`, `insertBetween` methods have been moved to `forum/components/SuperTextarea`. + +Also for `forum/components/TextEditor`, `this.disabled` is no longer used; `disabled` is passed in as an attr instead. It may be accessed externally via `app.composer.body.attrs.disabled`. + +Similarly to Modals and Alerts, `app.composer.load` no longer accepts a component instance. Instead, pass in the body class and any attrs. For instance, + +```js +// Mithril 0.2 +app.composer.load(new DiscussionComposer({user: app.session.user})); + +// Mithril 2 +app.composer.load(DiscussionComposer, {user: app.session.user}) +``` + +Finally, functionality for confirming before unloading a page with an active composer has been moved into the `common/components/ConfirmDocumentUnload` component. + +#### Widget and DashboardWidget + +The redundant `admin/components/Widget` component has been removed. `admin/components/DashboardWidget` should be used instead. + +#### NotificationList + +For `forum/components/NotificationList`, the `clear`, `load`, `loadMore`, `parseResults`, and `markAllAsRead` methods have been moved to `forum/states/NotificationListState`. + +Methods for `isLoading` and `hasMoreResults` have been added to `forum/states/NotificationListState`. + +`app.cache.notifications` is no longer available; `app.notifications` (which points to an instance of `NotificationListState`) should be used instead. + +#### Checkbox + +Loading state in the `common/components/Checkbox` component is no longer managed through `this.loading`; it is now passed in as a prop (`this.attrs.loading`). + +#### Preference Saver + +The `preferenceSaver` method of `forum/components/SettingsPage` has been removed without replacement. This is done to avoid saving component instances. Instead, preferences should be directly saved. Por ejemplo: + +```js +// Old way +Switch.component({ + children: app.translator.trans('core.forum.settings.privacy_disclose_online_label'), + state: this.user.preferences().discloseOnline, + onchange: (value, component) => { + this.user.pushAttributes({ lastSeenAt: null }); + this.preferenceSaver('discloseOnline')(value, component); + }, +}) + +// Without preferenceSaver +Switch.component({ + children: app.translator.trans('core.forum.settings.privacy_disclose_online_label'), + state: this.user.preferences().discloseOnline, + onchange: (value) => { + this.discloseOnlineLoading = true; + + this.user.savePreferences({ discloseOnline: value }).then(() => { + this.discloseOnlineLoading = false; + m.redraw(); + }); + }, + loading: this.discloseOnlineLoading, +}) +``` + +A replacement will eventually be introduced. + +#### DiscussionListState + +For `forum/components/DiscussionList`, the `requestParams`, `sortMap`, `refresh`, `loadResults`, `loadMore`, `parseResults`, `removeDiscussion`, and `addDiscussion` methods have been moved to `forum/states/DiscussionListState`. + +Methods for `hasDiscussions`, `isLoading`, `isSearchResults`, and `empty` have been added to `forum/states/DiscussionListState`. + +`app.cache.discussions` is no longer available; `app.discussions` (which points to an instance of `DiscussionListState`) should be used instead. + +#### PageState + +`app.current` and `app.previous` no longer represent component instances, they are now instances of the `common/states/PageState` class. This means that: + +- Instead of `app.current instanceof X`, use `app.current.matches(X)` +- Instead of `app.current.PROPERTY`, use `app.current.get('PROPERTY')`. Please note that all properties must be exposed EXPLICITLY via `app.current.set('PROPERTY', VALUE)`. + +#### PostStream + +Logic from `forum/components/PostStreamScrubber`'s `update` method has been moved to `forum/components/PostStream`'s `updateScrubber` method. + +For `forum/components/PostStream`, the `update`, `goToFirst`, `goToLast`, `goToNumber`, `goToIndex`, `loadNearNumber`, `loadNearIndex`, `loadNext`, `loadPrevious`, `loadPage`, `loadRange`, `show`, `posts`, `reset`, `count`, and `sanitizeIndex` methods have been moved to `forum/states/PostStreamState`. + +Methods for `disabled` and `viewingEnd` have been added to `forum/states/PostStreamState`. + +#### SearchState and GlobalSearchState + +As with other components, we no longer store instances of `forum/components/Search`. As such, every `Search` component instance should be paired with a `forum/states/SearchState` instance. + +At the minimum, `SearchState` contains the following methods: + +- getValue +- setValue +- clear +- cache (adds a searched value to cache, meaning that we don't need to search for its results again) +- isCached (checks if a value has been searched for before) + +All of these methods have been moved from `Search` to `SearchState`. Additionally, Search's `stickyParams`, `params`, `changeSort`, `getInitialSearch`, and `clearInitialSearch` methods have been moved to `forum/states/GlobalSearchState`, which is now available via `app.search`. + +To use a custom search, you'll want to: + +1. Possibly create a custom subclass of `SearchState` +2. Create a custom subclass of `Search`, which overrides the `selectResult` method to handle selecting results as needed by your use case, and modify the `sourceItems` methods to contain the search sources you need. + +#### moment -> dayjs + +The `moment` library has been removed, and replaced by the `dayjs` library. The global `moment` can still be used for now, but is deprecated. `moment` and `dayjs` have very similar APIs, so very few changes will be needed. Please see the dayjs documentation [for more information](https://day.js.org/en/) on how to use it. + +#### Subtree Retainer + +`SubtreeRetainer` is a util class that makes it easier to avoid unnecessary redraws by keeping track of some pieces of data. When called, it checks if any of the data has changed; if not, it indicates that a redraw is not necessary. + +In mithril 0.2, its `retain` method returned a [subtree retain directive](https://mithril.js.org/archive/v0.1.25/mithril.render.html#subtree-directives) if no redraw was necessary. + +In mithril 2, we use its `needsRebuild` method in combination with `onbeforeupdate`. Por ejemplo: + +```js +class CustomComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + this.showContent = false; + + this.subtree = new SubtreeRetainer( + () => this.showContent, + ) + } + + onbeforeupdate() { + // If needsRebuild returns true, mithril will diff and redraw the vnode as usual. Otherwise, it will skip this redraw cycle. + // In this example, this means that this component and its children will only be redrawn when extra content is toggled. + return this.subtree.needsRebuild(); + } + + view(vnode) { + return
+ +

Hello World!{this.showContent ? ' Extra Content!' : ''}

+
; + } +} +``` + +#### attrs() method + +Previously, some components would have an attrs() method, which provided an extensible way to provide attrs to the top-level child vnode returned by `view()`. For instance, + +```js +class CustomComponent extends Component { + view() { + return

Hello World!

; + } + + attrs() { + return { + className: 'SomeClass', + onclick: () => console.log('click'), + }; + } +} +``` + +Since `this.attrs` is now used for attrs passed in from parent components, `attrs` methods have been renamed to `elementAttrs`. + +#### Children and .component + +Previously, an element could be created with child elements by passing those in as the `children` prop: + +```js +Button.component({ + className: 'Button Button--primary', + children: 'Button Text' +}); +``` + +This will no longer work, and will actually result in errors. Instead, the 2nd argument of the `component` method should be used: + +```js +Button.component({ + className: 'Button Button--primary' +}, 'Button Text'); +``` + +Children can still be passed in through JSX: + +```js + +``` + +#### Tag attr + +Because mithril uses 'tag' to indicate the actual html tag (or component class) used for a vnode, you can no longer pass `tag` as an attr to components extending Flarum's `Component` helper class. The best workaround here is to just use another name for this attr. + +#### affixSidebar + +The `affixSidebar` util has been removed. Instead, if you want to affix a sidebar, wrap the sidebar code in an `AffixedSidebar` component. For instance, + +```js +class OldWay extends Component { + view() { + return
+
+
+ +
Actual Page Content
+
+
+
; + } +} + +class NewWay extends Component { + view() { + return
+
+
+ + + +
Actual Page Content
+
+
+
; + } +} +``` + +#### Fragment + +**Warning: For Advanced Use Only** + +In some rare cases, we want to have extremely fine grained control over the rendering and display of some significant chunks of the DOM. These are attached with `m.render`, and do not experience automated redraws. Current use cases in core and bundled extensions are: + +- The "Reply" button that shows up when selecting text in a post +- The mentions autocomplete menu that shows up when typing +- The emoji autocomplete menu that shows up when typing + +For this purpose, we provide a helper class (`common/Fragment`), of which you can create an instance, call methods, and render via `m.render(DOM_ROOT, fragmentInstance.render())`. The main benefit of using the helper class is that it allows you to use lifecycle methods, and to access the underlying DOM via `this.$()`, like you would be able to do with a component. + +This should only be used when absolutely necessary. If you are unsure, you probably don't need it. If the goal is to not store component instances, the "state pattern" as described above is preferable. + +### Required Frontend Changes Recap + +Each of these changes has been explained above, this is just a recap of major changes for your convenience. + +- Component Methods: + - `view()` -> `view(vnode)` + - Lifecycle + - `init()` -> `oninit(vnode)` + - `config()` -> Lifecycle hooks `oncreate(vnode)` / `onupdate(vnode)` + - `context.onunload()` -> `onremove()` + - `SubtreeRetainer` -> `onbeforeupdate()` + - if present, `attrs()` method needs to be renamed -> convention `elementAttrs()` + - building component with `MyComponent.component()` -> `children` is now second parameter instead of a named prop/attr (first argument) -> JSX preferred +- Routing + - `m.route()` -> `m.route.get()` + - `m.route(name)` -> `m.route.set(name)` + - register routes with page class, not instance + - special case when passing props + - `` -> `` +- AJAX + - `m.request({...})` -> `data:` key split up into `body:` and `params:` + - `m.deferred` -> native `Promise` +- Redrawing + - `m.redraw(true)` -> `m.redraw.sync()` + - `m.redraw.strategy('none')` -> `e.redraw = false` in event handler + - `m.lazyRedraw()` -> `m.redraw()` + +#### Deprecated changes + +For the following changes, we currently provide a backwards-compatibility layer. This will be removed in time for the stable release. The idea is to let you release a new version that's compatible with Beta 14 to your users as quickly as possible. When you have taken care of the changes above, you should be good to go. For the following changes, we have bought you time until the stable release. Considering you have to make changes anyway, why not do them now? + +- `this.props` -> `this.attrs` +- static `initProps()` -> static `initAttrs()` +- `m.prop` -> `flarum/utils/Stream` +- `m.withAttr` -> `flarum/utils/withAttr` +- `moment` -> `dayjs` + +## Backend (PHP) + +### New Features + +#### Extension Dependencies + +Some extensions are based on, or add features to, other extensions. Prior to this release, there was no way to ensure that those dependencies were enabled before the extension that builds on them. Now, you cannot enable an extension unless all of its dependencies are enabled, and you cannot disable an extension if there are other enabled extensions depending on it. + +So, how do we specify dependencies for an extension? Well, all you need to do is add them as composer dependencies to your extension's `composer.json`! For instance, if we have an extension that depends on Tags and Mentions, our `composer.json` will look like this: + +```json +{ + "name": "my/extension", + "description": "Cool New Extension", + "type": "flarum-extension", + "license": "MIT", + "require": { + "flarum/core": "^0.1.0-beta.14", + "flarum/tags": "^0.1.0-beta.14", // Will mark tags as a dependency + "flarum/mentions": "^0.1.0-beta.14", // Will mark mentions as a dependency + } + // other config +} +``` + +#### View Extender + +Previously, when extensions needed to register Laravel Blade views, they could inject a view factory in `extend.php` and call it's `addNamespace` method. For instance, + +```php +// extend.php +use Illuminate\Contracts\View\Factory; + +return [ + function (Factory $view) { + $view->addNamespace(NAME, RELATIVE PATH); + } +] +``` + +This should NOT be used, as it will break views for all extensions that boot after yours. Instead, the `View` extender should be used: + +```php +// extend.php +use Flarum\Extend\View; + +return [ + (new View)->namespace(NAME, RELATIVE PATH); +] +``` + +#### Application and Container + +Although Flarum uses multiple components of the Laravel framework, it is not a pure Laravel system. In beta 14, the `Flarum\Foundation\Application` class no longer implements `Illuminate\Contracts\Foundation\Application`, and no longer inherits `Illuminate\Container\Container`. Several things to note: + +- The `app` helper now points to an instance of `Illuminate\Container\Container`, not `Flarum\Foundation\Application`. You might need to resolve things through the container before using them: for instance, `app()->url()` will no longer work; you'll need to resolve or inject an instance of `Flarum\Foundation\Config` and use that. +- Injected or resolved instances of `Flarum\Foundation\Application` can no longer resolve things through container methods. `Illuminate\Container\Container` should be used instead. +- Not all public members of `Illuminate\Contracts\Foundation\Application` are available through `Flarum\Foundation\Application`. Please refer to our [API docs on `Flarum\Foundation\Application`](https://api.docs.flarum.org/php/master/flarum/foundation/application) for more information. + +#### Other Changes + +- We are now using Laravel 6. Please see [Laravel's upgrade guide](https://laravel.com/docs/6.x/upgrade) for more information. Please note that we do not use all of Laravel. +- Optional params in url generator now work. For instance, the url generator can now properly generate links to posts in discussions. +- A User Extender has been added, which replaces the deprecated `PrepareUserGroups` and `GetDisplayName` events. +- Error handler middleware can now be manipulated by the middleware extender through the `add`, `remove`, `replace`, etc methods, just like any other middleware. +- `Flarum/Foundation/Config` and `Flarum/Foundation/Paths` can now be injected where needed; previously their data was accessible through `Flarum/Foundation/Application`. + +### Deprecations + +- `url` provided in `config.php` is now an array, accessible via `$config->url()`, for an instance of `Config` - [PR](https://github.com/flarum/core/pull/2271#discussion_r475930358) +- AssertPermissionTrait has been deprecated - [Issue](https://github.com/flarum/core/issues/1320) +- Global path helpers and path methods of `Application` have been deprecated, the injectable `Paths` class should be used instead - [PR](https://github.com/flarum/core/pull/2155) +- `Flarum\User\Event\GetDisplayName` has been deprecated, the `displayNameDriver` method of the `User` extender should be used instead - [PR](https://github.com/flarum/core/pull/2174) + +### Removals + +- Do NOT use the old closure notation for configuring view namespaces. This will break all extensions that boot after your extension. The `View` extender MUST be used instead. +- app()->url() will no longer work: [`Flarum\Http\UrlGenerator`](routes.md) should be injected and used instead. An instance of `Flarum\Http\UrlGenerator` is available in `blade.php` templates via `$url`. +- As a part of the Laravel 6 upgrade, the [`array_` and `str_` helpers](https://laravel.com/docs/6.x/upgrade#helpers) have been removed. +- The Laravel translator interface has been removed; the Symfony translator interface should be used instead: `Symfony\Component\Translation\TranslatorInterface` +- The Mandrill mail driver is no longer provided in Laravel 6, and has been removed. +- The following events deprecated in Beta 13 [have been removed](https://github.com/flarum/core/commit/7d1ef9d89161363d1c8dea19cf8aebb30136e9e3#diff-238957b67e42d4e977398cd048c51c73): + - `AbstractConfigureRoutes` + - `ConfigureApiRoutes` - Use the `Routes` extender instead + - `ConfigureForumRoutes` - Use the `Frontend` or `Routes` extenders instead + - `ConfigureLocales` - Use the `LanguagePack` extender instead + - `ConfigureModelDates` - Use the `Model` extender instead + - `ConfigureModelDefaultAttributes` - Use the `Model` extender instead + - `GetModelRelationship` - Use the `Model` extender instead + - `Console\Event\Configuring` - Use the `Console` extender instead + - `BioChanged` - User bio has not been a core feature for several releases diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md new file mode 100644 index 000000000..b1577b12c --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md @@ -0,0 +1,60 @@ +# Updating For Beta 15 + +Beta 15 features multiple new extenders, a total redesign of the admin dashboard, and several other interesting new features for extensions. As before, we have done our best to provide backwards compatibility layers, and we recommend switching away from deprecated systems as soon as possible to make your extensions more stable. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## New Features / Deprecations + +### Extensores + +- `Flarum\Api\Event\WillGetData` and `Flarum\Api\Event\WillSerializeData` have been deprecated, the `ApiController` extender should be used instead +- `Flarum\Api\Event\Serializing` and `Flarum\Event\GetApiRelationship` have been deprecated, the `ApiSerializer` extender should be used instead +- `Flarum\Formatter\Event\Parsing` has been deprecated, the `parse` method of the `Formatter` extender should be used instead +- `Flarum\Formatter\Event\Rendering` has been deprecated, the `render` method of the `Formatter` extender should be used instead +- `Flarum\Notification\Event\Sending` has been deprecated, the `driver` method of the `Notification` extender should be used instead + - Please note that the new notification driver system is not an exact analogue of the old `Sending` event, as it can only add new drivers, not change the functionality of the default notification bell alert driver. If your extension needs to modify **how** or **to whom** notifications are sent, you may need to replace `Flarum\Notification\NotificationSyncer` on the service provider level +- `Flarum\Event\ConfigureNotificationTypes` has been deprecated, the `type` method of the `Notification` extender should be used instead +- `Flarum\Event\ConfigurePostTypes` has been deprecated, the `type` method of the `Post` extender should be used instead +- `Flarum\Post\Event\CheckingForFlooding` has been deprecated, as well as `Flarum\Post\Floodgate`. They have been replaced with a middleware-based throttling system that applies to ALL requests to /api/*, and can be configured via the `ThrottleApi` extender. Please see our [api-throttling](api-throttling.md) documentation for more information. +- `Flarum\Event\ConfigureUserPreferences` has been deprecated, the `registerPreference` method of the `User` extender should be used instead +- `Flarum\Foundation\Event\Validating` has been deprecated, the `configure` method of the `Validator` extender should be used instead + +- The Policy system has been reworked a bit to be more intuitive. Previously, policies contained both actual policies, which determine whether a user can perform some ability, and model visibility scopers, which allowed efficient restriction of queries to only items that users have access to. See the [authorization documentation](authorization.md) for more information on how to use the new systems. Now: + - `Flarum\Event\ScopeModelVisibility` has been deprecated. New scopers can be registered via the `ModelVisibility` extender, and any `Eloquent\Builder` query can be scoped by calling the `whereVisibleTo` method on it, with the ability in question as an optional 2nd argument (defaults to `view`). + - `Flarum\Event\GetPermission` has been deprecated. Policies can be registered via the `Policy` extender. `Flarum\User\User::can` has not changed. Please note that the new policies must return one of `$this->allow()`, `$this->deny()`, `$this->forceAllow()`, `$this->forceDeny()`, not a boolean. + +- A `ModelUrl` extender has been added, allowing new slug drivers to be registered. This accompanies Flarum's new slug driving system, which allows for extensions to define custom slugging strategies for sluggable models. The extender supports sluggable models outside of Flarum core. Please see our [model slugging](slugging.md) documentation for more information. +- A `Settings` extender has been added, whose `serializeToForum` method makes it easy to serialize a setting to the forum. +- A `ServiceProvider` extender has been added. This should be used with extreme caution for advanced use cases only, where there is no alternative. Please note that the service provider layer is not considered public API, and is liable to change at any time, without notice. + +### Admin UX Redesign + +The admin dashboard has been completely redesigned, with a focus on providing navbar pages for each extension. The API for extensions to register settings, permissions, and custom pages has also been greatly simplified. You can also now update your extension's `composer.json` to provide links for funding, support, website, etc that will show up on your extension's admin page. Please see [our Admin JS documentation](admin.md) for more information on how to use the new system. + +### Other New Features + +- On the backend, the route name is now available via `$request->getAttribute('routeName')` for controllers, and for middleware that run after `Flarum\Http\Middleware\ResolveRoute.php`. +- `Flarum\Api\Controller\UploadImageController.php` can now be used as a base class for controllers that upload images (like for the logo and favicon). +- Automatic browser scroll restoration can now be disabled for individual pages [see our frontend page documentation for more info](frontend-pages.md). + +## Breaking Changes + +- The following deprecated frontend BC layers were removed: + - `momentjs` no longer works as an alias for `dayjs` + - `this.props` and `this.initProps` no longer alias `this.attrs` and `this.initAttrs` for the `Component` base class + - `m.withAttr` and `m.stream` no longer alias `flarum/utils/withAttr` and `flarum/utils/Stream` + - `app.cache.discussionList` has been removed + - `this.content` and `this.editor` have been removed from `ComposerBody` + - `this.component`, `this.content`, and `this.value` have been removed from `ComposerState` +- The following deprecated backend BC layers were removed: + - The `publicPath`, `storagePath`, and `vendorPath` methods of `Flarum\Foundation\Application` have been removed + - The `base_path`, `public_path`, and `storage_path` global helpers have been removed + - The `getEmailSubject` method of `Flarum\Notification\MailableInterface` MUST now take a translator instance as an argument + - `Flarum\User\AssertPermissionTrait` has been removed, the analogous methods on `Flarum\User\User` should be used instead + - The `Flarum\Event\PrepareUserGroups` event has been removed, use the `User` extender instead + - The `Flarum\User\Event\GetDisplayName` event has been removed, use the display name driver feature of the `User` extender instead diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md new file mode 100644 index 000000000..86ee1ac8f --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md @@ -0,0 +1,138 @@ +# Actualización para la Beta 16 + +La Beta 16 finaliza la API del extensor de PHP, introduce una biblioteca de pruebas y tipificaciones JS, cambia al uso de espacios de nombres para las importaciones JS, aumenta la robustez de las dependencias de la extensión y permite anular rutas, entre otras características. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Frontend + +- Se ha introducido una nueva abstracción del controlador del editor, que permite a las extensiones sustituir el editor por defecto basado en el área de texto por soluciones más avanzadas. +- Los componentes `TextEditor` y `TextEditorButton`, así como la utilidad `BasicEditorDriver` (que sustituye a `SuperTextarea`) han sido trasladados de `forum` a `common`. +- Los espacios de nombres `forum`, `admin` y `common` deben ser utilizados al importar. Así que en lugar de `importar Componente de 'flarum/Component'`, utilice `importar Componente de 'flarum/common/Component`. El soporte para los antiguos estilos de importación será retirado en la versión estable, y se eliminará con Flarum 2.0. +- Se ha liberado una librería de escritura para soportar el autocompletado del editor para el desarrollo del frontend, y puede ser instalada en su entorno de desarrollo mediante `npm install --save-dev flarum@0.1.0-beta.16`. +- Las categorías de las extensiones se han simplificado a `feature`, `theme` e `language`. + +## Backend + +### Extensores + +- Todos los extensores que soportan callbacks/cierres ahora soportan funciones globales como `'boolval'` y funciones de tipo array como `[ClassName::class, 'methodName']`. +- El método `SerializeToFrontend` del extensor `Settings` soporta ahora un valor por defecto como cuarto argumento. +- El extensor `Event` ahora soporta el registro de suscriptores para múltiples eventos a la vez a través de un método `subscribe`. +- El extensor `Notification` tiene ahora un método `beforeSending`, que permite ajustar la lista de destinatarios antes de enviar una notificación. +- El método `mutate` del `ApiSerializer` ha quedado obsoleto, y se ha renombrado a `attributes`. +- Los métodos `remove` de los extensores `Route` y `Frontend` pueden utilizarse para eliminar (y luego reemplazar) rutas. +- El extensor `ModelPrivate` sustituye al evento `GetModelIsPrivate`, que ha quedado obsoleto. +- Los métodos del extensor `Auth` sustituyen al evento `CheckingPassword`, que ha quedado obsoleto. +- Todos los eventos relacionados con la búsqueda están ahora obsoletos en favor de los extensores `SimpleFlarumSearch` y `Filter`; esto se explica con más detalle a continuación. + +### Laravel y Symfony + +La Beta 16 actualiza de la v6.x a la v8.x de los componentes de Laravel y de la v4 a la v5 de los componentes de Symfony. Por favor, consulta las respectivas guías de actualización de cada una de ellas para conocer los cambios que puedes necesitar en tus extensiones. El cambio más aplicable es la desaparición de `Symfony\Component\Translation\TranslatorInterface` en favor de `Symfony\Contracts\Translation\TranslatorInterface`. El primero se eliminará en la beta 17. + +### Funciones de Ayuda + +Las restantes funciones globales de ayuda `app` y `event` han quedado obsoletas. La función `app` ha sido reemplazada por `resolve`, que toma el nombre de un enlace del contenedor y lo resuelve a través del contenedor. + +Dado que algunas extensiones de Flarum utilizan bibliotecas de Laravel que asumen la existencia de algunos helpers globales, hemos recreado algunos helpers de uso común en el paquete [flarum/laravel-helpers](https://github.com/flarum/laravel-helpers). Estos helpers NO deben usarse directamente en el código de las extensiones de Flarum; están disponibles para que las bibliotecas basadas en Laravel que esperan que existan no funcionen mal. + +### Cambios en la búsqueda + +Como parte de nuestros esfuerzos para hacer el sistema de búsqueda de Flarum más flexible, hemos hecho varias refacciones en la beta 16. En particular, el filtrado y la búsqueda se tratan ahora como mecanismos diferentes, y tienen conductos y extensores separados. Esencialmente, si una consulta tiene un parámetro de consulta `filter[q]`, será tratada como una búsqueda, y todos los demás parámetros de filtro serán ignorados. En caso contrario, será tratada por el sistema de filtrado. Esto permitirá eventualmente que las búsquedas sean manejadas por controladores alternativos (provistos por extensiones), como ElasticSearch, sin afectar el filtrado (por ejemplo, cargar discusiones recientes). Las clases comunes a ambos sistemas se han trasladado a un espacio de nombres `Query`. + +Las implementaciones de filtrado y de búsqueda por defecto de Core (denominadas SimpleFlarumSearch) son bastante similares, ya que ambas se alimentan de la base de datos. Los controladores de la API `List` llaman a los métodos `search` / `filter` en una subclase específica de recursos de `Flarum\Search\AbstractSearcher` o `Flarum\Filter\AbstractFilterer`. Los argumentos son una instancia de `Flarum\Query\QueryCriteria`, así como información de ordenación, desplazamiento y límite. Ambos sistemas devuelven una instancia de `Flarum\Query\QueryResults`, que es efectivamente una envoltura alrededor de una colección de modelos Eloquent. + +Los sistemas por defecto también son algo similares en su implementación. El `Filterer` aplica filtros (implementando la `Flarum\Filter\FilterInterface`) basándose en los parámetros de consulta de la forma `filter[FILTER_KEY] = FILTER_VALUE` (o `filter[-FILTER_KEY] = FILTER_VALUE` para filtros negados). El `Searcher` de SimpleFlarumSearch divide el parámetro `filter[q]` por espacios en "términos", aplica Gambits (implementando `Flarum\Search\GambitInterface`) que coinciden con los términos, y luego aplica un "Fulltext Gambit" para buscar basado en cualquier "término" que no coincida con un Gambit auxiliar. Ambos sistemas aplican entonces una ordenación, un desplazamiento y un límite de recuento de resultados, y permiten que las extensiones modifiquen el resultado de la consulta mediante `searchMutators` o `filterMutators`. + +Las extensiones añaden gambits y mutadores de búsqueda y establecen gambits de texto completo para las clases `Searcher` mediante el extensor `SimpleFlarumSearch`. Pueden añadir filtros y mutadores de filtro a las clases `Filterer` mediante el extensor `Filter`. + +Con respecto a la actualización, tenga en cuenta lo siguiente: + +- Las mutaciones de búsqueda registradas al escuchar los eventos de `Searching` para discusiones y usuarios se aplicarán como a las búsquedas durante el paso de mutación de búsqueda a través de una capa temporal de BC. NO se aplicarán a los filtros. Este es un cambio de última hora. Estos eventos han quedado obsoletos. +- Los gambits de búsqueda registrados al escuchar los eventos `ConfigureUserGambits` y `ConfigureDiscussionGambits` se aplicarán a las búsquedas a través de una capa temporal de BC. NO se aplicarán a los filtros. Este es un cambio de última hora. Estos eventos han quedado obsoletos. +- Los filtros de entrada registrados mediante la escucha de los eventos `ConfigurePostsQuery` se aplicarán a los filtros de entrada a través de una capa temporal de BC. Este evento ha quedado obsoleto. + +### Biblioteca de pruebas + +El paquete `flarum/testing` proporciona utilidades para las pruebas automatizadas de backend impulsadas por PHPUnit. Vea la [documentación de pruebas](testing.md) para más información. + +### Dependencias Opcionales + +La beta 15 introdujo las "dependencias de la extensión", que requieren que cualquier extensión listada en la sección `composer.json` de tu extensión esté habilitada antes de que tu extensión pueda ser activada. + +Con la beta 16, puedes especificar "dependencias opcionales" listando los nombres de sus paquetes de compositor como un array en la sección `extra.flarum-extension.optional-dependencies` de tu extensión. Todas las dependencias opcionales habilitadas se iniciarán antes que su extensión, pero no son necesarias para que su extensión esté habilitada. + +### Cambios en el token de acceso y la autenticación + +#### Cambios en la API de extensión + +La firma de varios métodos relacionados con la autenticación se han cambiado para tomar `$token` como parámetro en lugar de `$userId`. Otros cambios son el resultado del paso de `$lifetime` a `$type`. + +- `Flarum\Http\AccessToken::generate($userId)` ya no acepta `$lifetime` como segundo parámetro. El parámetro se ha mantenido por compatibilidad con versiones anteriores, pero no tiene ningún efecto. Se eliminará en la beta 17. +- Para crear tokens de acceso recordables se debe utilizar `Flarum\Http\RememberAccessToken::generate($userId)`. +- `Flarum\Http\DeveloperAccessToken::generate($userId)` debe usarse para crear tokens de acceso para desarrolladores (no caducan). +- `Flarum\Http\SessionAccessToken::generate()` puede ser usado como un alias de `FlarumHttpAccessToken::generate()`. Es posible que en el futuro desaparezca `AccessToken::generate()`. +- `Flarum\Http\Rememberer::remember(ResponseInterface $response, AccessToken $token)`: pasar un `AccessToken` ha quedado obsoleto. Pasa una instancia de `RememberAccessToken` en su lugar. Como capa de compatibilidad temporal, pasar cualquier otro tipo de token lo convertirá en un remember token. En la beta 17 la firma del método cambiará para aceptar sólo `RememberAccessToken`. +- El método `Flarum\Http\Rememberer::rememberUser()` ha quedado obsoleto. En su lugar debe crear/recuperar un token manualmente con `RememberAccessToken::generate()` y pasarlo a `Rememberer::remember()`. +- El segundo parámetro de `Flarum\Http\SessionAuthenticator::logIn(Session $session, $userId)` ha quedado obsoleto y se sustituye por `$token`. Se mantiene la compatibilidad con versiones anteriores. En la beta 17, la firma del método del segundo parámetro cambiará a `AccessToken $token`. +- Ahora `AccessToken::generate()` guarda el modelo en la base de datos antes de devolverlo. +- Ya no se puede utilizar `AccessToken::find($id)` o `::findOrFail($id)` para encontrar un token, porque la clave primaria ha cambiado de `token` a `id`. En su lugar puedes utilizar `AccessToken::findValid($tokenString)`. +- Se recomienda utilizar `AccessToken::findValid($tokenString): AccessToken` o `AccessToken::whereValid(): Illuminate\Database\Eloquent\Builder` para encontrar un token. Esto hará que la solicitud se amplíe automáticamente para que sólo devuelva tokens válidos. En los foros con poca actividad, esto aumenta la seguridad, ya que la eliminación automática de tokens obsoletos sólo ocurre cada 50 solicitudes en promedio. + +#### Cambios en la sesión de Symfony + +Si estás accediendo o manipulando directamente el objeto de sesión de Symfony, se han realizado los siguientes cambios: + +- El atributo `user_id` ya no se utiliza. Se ha añadido el atributo `access_token` como reemplazo. Es una cadena que mapea a la columna `token` de la tabla de base de datos `access_tokens`. + +Para recuperar el usuario actual desde dentro de una extensión de Flarum, la solución ideal que ya estaba presente en Flarum es utilizar `$request->getAttribute('actor')` que devuelve una instancia de `User` (que podría ser `Guest`) + +Para recuperar la instancia del token desde Flarum, puede utilizar `Flarum\Http\AccessToken::findValid($tokenString)`. + +Para recuperar los datos del usuario desde una aplicación que no sea de Flarum, tendrá que hacer una petición adicional a la base de datos para recuperar el token. El ID de usuario está presente como `user_id` en la tabla `access_tokens`. + +#### Cambios en la creación de tokens + +Se ha eliminado la propiedad `lifetime` de los tokens de acceso. Los tokens son ahora o bien tokens `session` con un tiempo de vida de 1h después de la última actividad, o bien tokens `session_remember` con un tiempo de vida de 5 años después de la última actividad. + +El parámetro `remember` que antes estaba disponible en el punto final `POST /login` se ha hecho disponible en `POST /api/token`. No devuelve la cookie de recuerdo en sí, pero el token devuelto puede utilizarse como cookie de recuerdo. + +El parámetro `lifetime` de `POST /api/token` ha quedado obsoleto y será eliminado en la beta 17. Se ha proporcionado una compatibilidad parcial con el pasado donde un valor de `lifetime` superior a 3600 segundos se interpreta como `remember=1`. Los valores inferiores a 3600 segundos resultan en un token normal no recordado. + +Se han introducido nuevos tokens de `developer` que no caducan, aunque actualmente no pueden crearse a través de la API REST. Los desarrolladores pueden crear tokens de desarrollador desde una extensión usando `Flarum\Http\DeveloperAccessToken::generate($userId)`. + +Si ha creado manualmente tokens en la base de datos desde fuera de Flarum, la columna `type` es ahora obligatoria y debe contener `session`, `session_remember` o `developer`. Los tokens de tipo no reconocido no podrán ser utilizados para autenticarse, pero tampoco serán eliminados por el recolector de basura. En una futura versión las extensiones podrán registrar tipos de token de acceso personalizados. + +#### Cambios en el uso de los tokens + +Un [problema de seguridad en Flarum](https://github.com/flarum/core/issues/2075) provocaba anteriormente que todos los tokens no caducaran nunca. Esto tenía un impacto de seguridad limitado debido a que los tokens son caracteres únicos largos. Sin embargo, las integraciones personalizadas que guardaban un token en una base de datos externa para su uso posterior podían encontrar que los tokens ya no funcionaban si no se utilizaban recientemente. + +Si utiliza tokens de acceso de corta duración para cualquier propósito, tenga en cuenta el tiempo de caducidad de 1h. La caducidad se basa en la hora del último uso, por lo que seguirá siendo válida mientras se siga utilizando. + +Debido a la gran cantidad de tokens caducados acumulados en la base de datos y al hecho de que la mayoría de los tokens no se utilizaron nunca más de una vez durante el proceso de inicio de sesión, hemos tomado la decisión de eliminar todos los tokens de acceso con una vida útil de 3600 segundos como parte de la migración, Todos los tokens restantes se han convertido en tokens `session_remember`. + +#### Cookie de Recuerdo + +La cookie de recuerdo sigue funcionando como antes, pero se han hecho algunos cambios que podrían romper implementaciones inusuales. + +Ahora sólo los tokens de acceso creados con la opción `remember` pueden ser utilizados como cookie remember. Cualquier otro tipo de token será ignorado. Esto significa que si creas un token con `POST /api/token` y luego lo colocas en la cookie manualmente, asegúrate de establecer `remember=1` al crear el token. + +#### Expiración de la sesión web + +En versiones anteriores de Flarum, una sesión podía mantenerse viva para siempre hasta que los archivos de sesión de Symfony fueran borrados del disco. + +Ahora las sesiones están vinculadas a tokens de acceso. Si un token se borra o expira, la sesión web vinculada terminará automáticamente. + +Un token vinculado a una sesión web ahora se eliminará automáticamente de la base de datos cuando el usuario haga clic en el cierre de sesión. Esto evita que cualquier token robado sea reutilizado, pero podría romper la integración personalizada que anteriormente utilizaba un único token de acceso tanto en una sesión web como en otra cosa. + +### Varios + +- La dirección IP está ahora disponible en las peticiones a través de `$request->getAttribute('ipAddress')`. +- Las políticas ahora pueden devolver `true` y `false` como alias para `$this->allow()` y `$this->deny()`, respectivamente. +- El permiso `user.edit` se ha dividido en `user.editGroups`, `user.editCredentials` (para correo electrónico, nombre de usuario y contraseña) y `user.edit` (para otros atributos). +- Ahora hay permisos (`bypassTagCounts`) que permiten a los usuarios saltarse los requisitos de recuento de etiquetas. +- Flarum ahora soporta PHP 7.3 - PHP 8.0, con soporte para PHP 7.2 oficialmente eliminado. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md new file mode 100644 index 000000000..f1324800c --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md @@ -0,0 +1,114 @@ +# Updating For Beta 8 + +All extensions will need to be refactored in order to work with beta 8. Here are the main things you will need to do in order to make your extension compatible. + +:::caution + +This guide is not comprehensive. You may encounter some changes we haven't documented. If you need help, start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## PHP Namespaces + +Beta 8 comes with large changes to the overall structure of the PHP backend. You will need to look through [this list](https://discuss.flarum.org/d/6572-help-us-namespace-changes) of namespace changes and make changes to your extension accordingly. + +[This script](https://gist.github.com/tobyzerner/55e7c05c95404e5efab3a9e43799d375) can help you to automate most of the namespace changes. Of course, you should still test your extension after running the script as it may miss something. + +## Database Naming + +Many database columns and JSON:API attributes have been renamed to conform to a [convention](/contributing.md#database). You will need to update any instances where your extension interacts with core data. You can see the changes in [#1344](https://github.com/flarum/core/pull/1344/files). + +## Extensores + +Beta 8 introduces a new concept called **extenders** that replace the most common event listeners. You can learn more about how they work in the [updated extension docs](start.md#extenders). + +`bootstrap.php` has been renamed to `extend.php` and returns an array of extender instances and functions: + +```php +use Flarum\Extend; + +return [ + (new Extend\Frontend('forum')) + ->js(__DIR__.'/js/dist/forum.js') + ->css(__DIR__.'/less/forum.less') + ->route('/t/{slug}', 'tag') + ->route('/tags', 'tags'), + + function (Dispatcher $events) { + $events->subscribe(Listener\AddForumTagsRelationship::class); + } +] +``` + +If you're listening for any of the following events, you'll need to update your code to use an extender instead. See the relevant docs for more information. + +| Event | Extender | +| ------------------------------------- | --------------------------- | +| `Flarum\Event\ConfigureFormatter`* | `Flarum\Extend\Formatter` | +| `Flarum\Event\ConfigureWebApp`* | `Flarum\Extend\Frontend` | +| `Flarum\Event\ConfigureClientView`* | `Flarum\Extend\Frontend` | +| `Flarum\Event\ConfigureLocales` | `Flarum\Extend\Locales` | +| `Flarum\Event\ConfigureApiRoutes` | `Flarum\Extend\Routes` | +| `Flarum\Event\ConfigureForumRoutes` | `Flarum\Extend\Routes` | + +_\* class no longer exists_ + +## JavaScript Tooling + +Previously Flarum and its extensions used a custom Gulp workflow to compile ES6 source code into something that browsers could understand. Beta 8 switches to a more conventional approach with Webpack. + +You will need to tweak the structure of your extension's `js` directory. Currently, your JS file hierarchy looks something like the following: + +``` +js +├── admin +│ ├── src +│ │ └── main.js +│ ├── dist +│ │ └── extension.js +│ ├── Gulpfile.js +│ └── package.json +└── forum + ├── src + │ └── main.js + ├── dist + │ └── extension.js + ├── Gulpfile.js + └── package.json +``` + +You'll need to make the following changes: + +1. Update `package.json` and create `webpack.config.js`, `forum.js`, and `admin.js` files using [these templates](frontend.md#transpilation). + +2. Inside your `admin` and `forum` *folders*, delete `Gulpfile.js`, `package.json`, and `dist`. Then inside each `src` folder, rename `main.js` to `index.js`. Now move all of the `src` files outside of `src` folder and delete it. + +3. In the root `js` folder create a folder called `src` and move your `admin` and `forum` *folders* into it. + +4. While still in your root `js` folder, run `npm install` and then `npm run build` to build the new JS dist files. + +If everything went right, your folder structure should look something like this: + +``` +js +├── src +│ ├── admin +│ │ └── index.js +│ └── forum +│ └── index.js +├── dist +│ ├── admin.js +│ ├── admin.js.map +│ ├── forum.js +│ └── forum.js.map +├── admin.js +├── forum.js +├── package.json +└── webpack.config.js +``` + +Take a look at the [bundled extensions](https://github.com/flarum) for more examples. + +## Font Awesome Icons + +Beta 8 upgrades to Font Awesome 5, in which icon class names have changed. The `flarum/helpers/icon` helper now requires the **full Font Awesome icon class names** to be passed, eg. `fas fa-bolt`. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/views.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/views.md new file mode 100644 index 000000000..fc4a75a86 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extend/views.md @@ -0,0 +1,63 @@ +# Views and Blade + +Although the Flarum UI you know and love is powered by our [Mithril frontend](frontend), server-side generated templates are still used throughout Flarum. Most notably, the HTML skeleton of the forum, which includes various SEO meta tags, as well as the no-js view of the forum, is implemented through the Views and Blade systems. + +[Blade](https://laravel.com/docs/8.x/blade) is Laravel's templating engine, which allows you to conveniently generate HTML (or other static content) from PHP. It's the same idea as [Jinja](https://jinja.palletsprojects.com/en/3.0.x/) or [EJS](https://ejs.co/). [Views](https://laravel.com/docs/8.x/views) are Laravel's system for organizing/registering Blade templates, and also includes utilities for rendering them and providing them with variables. + +For our purposes, views are directories containing `.blade.php` template files (possibly contained in subdirectories). + +## Adding Views + +You will need to tell the view factory where it can find your extension's view files by adding a `View` extender to `extend.php`: + +```php +use Flarum\Extend; +use Illuminate\Contracts\View\Factory; + +return [ + (new Extend\View) + ->namespace('acme.hello-world', __DIR__.'/views'), +]; +``` + + +## Blade Templates + +To learn about the syntax for Blade templates, read [Laravel's documentation](https://laravel.com/docs/8.x/blade). + +Once you've set up your views, you can render them to strings: + +```php +// Here, $view is of type `Illuminate\Contracts\View\Factory` +$renderedString = $view->make('acme.hello-world::greeting')->render(); + +// You can also pass variables to the view: +$renderedString = $view->make('acme.hello-world::greeting', ['varName' => true])->render(); +``` + +You can obtain the view factory instance through dependency injection. + +The format is `"VIEW_NAMESPACE::VIEW_NAME"`. If the view folder is organized as subdirectories, replace `/` with `.` in the pack. So if you have a file at `"forum/error.blade.php"` in a namespace called `"custom-views"`, you would use `"custom-views::forum.error"`. + +Note that all Blade templates rendered this way automatically have access to the following variables: + +- `$url`: a [URL generator](routes#generating-urls) instance. +- `$translator`: a [Translator](i18n#server-side-translation) instance. +- `$settings`: a [SettingsInterface](settings) instance. +- `$slugManager`: a [SlugManager](slugging) instance. + +Additionally, templates used by [content logic](routes#content) have access to `$forum`, which represents the [Forum API Document's attributes](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Serializer/ForumSerializer.php#L19). + +## Overriding Views + +If you want to override templates added by core or extensions, set up a view folder structure matching the one you are trying to override, containing just the files you are trying to override. Then use the `View` extender's `extendNamespace` method: + +```php +use Flarum\Extend; +use Illuminate\Contracts\View\Factory; + +return [ + (new Extend\View) + ->extendNamespace('acme.hello-world', __DIR__.'/override_views'); +]; +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extenders.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extenders.md new file mode 100644 index 000000000..c680b9932 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extenders.md @@ -0,0 +1,23 @@ +# Local Extenders + +If there are customizations you want to make to your site without distributing an entire extension, you can do so by using **local extenders**. Each Flarum installation comes with an `extend.php` file where you can add extender instances, just like in a full extension. + +See our [extension documentation](extend/start.md) for more information about extenders (and even an [example of a local extender](extend/start.md#hello-world)). + +If you need to create new files (when adding a custom class to be imported for extenders), you'll need to adjust your composer.json a bit. Add the following: + +```json +"autoload": { + "psr-4": { + "App\\": "app/" + } +}, +``` + +Now you can create new PHP files in an `app` subdirectory using the `App\...` namespace. + +:::tip Local Extenders vs Extensions + +Local extenders can be good for small tweaks, but if you need large customizations, an extension might be a better choice: a separate codebase, cleaner handling of many files, developer tooling, and the ability to easily open source are big benefits. + +::: diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/extensions.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extensions.md new file mode 100644 index 000000000..a168cb229 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/extensions.md @@ -0,0 +1,118 @@ +# Extensiones + +Flarum es minimalista, pero también es altamente extensible. De hecho, ¡la mayoría de las características que vienen con Flarum son en realidad extensiones! + +Este enfoque hace que Flarum sea extremadamente personalizable: Puedes desactivar cualquier característica que no necesites, e instalar otras extensiones para que tu foro sea perfecto para tu comunidad. + +Para más información sobre la filosofía de Flarum en cuanto a las características que incluimos en el núcleo, o si está buscando hacer su propia extensión, por favor vea nuestra [documentación de extensiones](extend/README.md). Este artículo se centrará en la gestión de las extensiones desde la perspectiva de un administrador del foro. + +## Extension Manager + +The extension manager is an extension that comes bundled with Flarum when installed via an archive. It provides a graphical interface for installing and updating both extensions and Flarum itself. + +If you do not have the extension manager installed and you wish to install it, you can do so by running the following command in your Flarum directory: + +```bash +composer require flarum/extension-manager:"*" +``` + +:::warning + +The extension manager allows an admin user to install any composer package. Only install the extension manager if you trust all of your forum admins with such permissions. + +::: + +![extension manager admin page](https://github.com/flarum/docs/assets/20267363/d0e1f7a5-e194-4acd-af63-7b8ddd95c26b) + + +## Encontrando Extensiones + +Flarum tiene un amplio ecosistema de extensiones, la mayoría de las cuales son de código abierto y gratuitas. Para encontrar nuevas e increíbles extensiones, visita la etiqueta [Extensiones](https://discuss.flarum.org/t/extensions) en los foros de la comunidad de Flarum. La base de datos no oficial [Extiverse extension database](https://extiverse.com/) es también un gran recurso. + +## Instalación de Extensiones + +### Through the interface + +Using the extension manager extension, you can install extensions directly from the admin dashboard. Once you have browsed the list of available extensions from the links above, and found one you want to install, you can install it by entering the extension's composer package name into the extension manager's installation input. + +![Installing an extension](/en/img/install-extension.png) + +### Through the command line + +Al igual que Flarum, las extensiones se instalan a través de [Composer](https://getcomposer.org), usando SSH. Para instalar una extensión típica: + +1. `cd` to your Flarum directory. `cd` a la carpeta que contiene el archivo `composer.json`. You can check directory contents via `ls -la`. +2. Run `composer require COMPOSER_PACKAGE_NAME:*`. Esto debería ser proporcionado por la documentación de la extensión. + +## Gestión de Extensiones + +### Through the interface + +Using the extension manager extension, you can update extensions directly from the admin dashboard. You can run a check for updates by clicking the "Check for updates" button in the extension manager. If there are updates available, you can update all extensions by clicking the "Global update" button. Or, you can update individual extensions by clicking the "Update" button next to the extension you want to update. + +![Updating an extension](/en/img/update-extension.png) + +### Through the command line + +Follow the instructions provided by extension developers. If you're using `*` as the version string for extensions ([as is recommended](composer.md)), running the commands listed in the [Flarum upgrade guide](update.md) should update all your extensions. + +## Uninstalling Extensions + +### Through the interface + +Using the extension manager extension, you can uninstall extensions directly from the admin dashboard. You can uninstall an extension by clicking the "Uninstall" button next to the extension you want to uninstall inside the extension's page. + +![Uninstalling an extension](/en/img/uninstall-extension.png) + +### Through the command line + +Similarly to installation, to remove an extension: + +0. If you want to remove all database tables created by the extension, click the "Purge" button in the admin dashboard. See [below](#managing-extensions) for more information. +1. `cd` to your Flarum directory. +2. Ejecute `composer require COMPOSER_PACKAGE_NAME`. Esto debería ser proporcionado por la documentación de la extensión. + +## Managing Extensions + +Each individual extension page of the admin dashboard provides a convenient way to manage the extension. Puede: + +- Enable or disable the extension. +- See the settings provided by the extension, and change them. +- Revert an extension's migrations to remove any database modifications it made (this can be done with the Purge button). Esto eliminará TODOS los datos asociados a la extensión, y es irreversible. Sólo se debe hacer cuando se está eliminando una extensión, y no se planea instalarla de nuevo. Es totalmente opcional. +- See the extension's README, if it has one. +- See the extension's version. +- Uninstall the extension if the extension manager is installed. + +## Configuring additional extension repository sources + +The extension manager uses `composer` under the hood, and as such, it looks for extension packages in the same places as `composer`. By default, this is [Packagist](https://packagist.org/). However, you can configure additional sources for the extension manager to look for extensions in. This is useful if you want to install an extension that is not available on Packagist. + +In the admin page of the extension manager, clicking the **Add Repository** button will open a modal where you can enter the name and URL of the repository you want to add. The name is just a label for the repository, and can be anything you want. The URL should be the URL of the repository which depends on the type of repository you want to add. + +### Adding a repository from a VCS + +If you want to add a repository from a VCS (e.g. GitHub, GitLab, BitBucket, etc), the URL should be the URL of the repository's VCS. For example, if you had a private GitHub repository at `https://github.com/acme/flarum-extension`, you would enter that URL into the URL field. If it is a private source, you will need to enter an authentication method through the **New authentication method** button. The token can be generated from your VCS provider's website, and the host should be the domain of the VCS provider (e.g. `github.com`). + +### Adding a composer repository + +Extiverse provides access to premium extensions. It is a good example of a composer repository. You would specify the URL as `https://flarum.org/composer/` and the name as `premium`. You would also need to enter an authentication method through the **New authentication method** button. The token can be generated from your Flarum account's [subscriptions](https://flarum.org/dashboard/subscriptions) page with the Instructions button. + +* Type: `HTTP Bearer` +* Host: `flarum.org` + +![Configure repositories](/en/img/config-repositories.png) + +:::info + +The configured repositories and auth methods will be active for both the command line and the admin dashboard. If you configure them from the command line however, you must not include the flag `--global`. + +::: + +## Installing Non-stable extensions + +If for whatever reason you want to install a non-stable extension (e.g. a beta, alpha or RC version) you must first update the **Minimum stability** setting to the wanted stability. + +* If you set it to Alpha, you will be able to install alpha, beta, RC (Release Candidate) and stable versions. +* If you set it to Beta, you will be able to install beta, RC and stable versions. +* If you set it to RC, you will be able to install RC and stable versions. +* If you set it to Stable, you will only be able to install stable versions. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/faq.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/faq.md new file mode 100644 index 000000000..25b9803fe --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/faq.md @@ -0,0 +1,35 @@ +# FAQ + +### ¿Cuándo será estable Flarum? + +Yes! After 6 years of development, Flarum 1.0.0 is finally here. + +### ¿Podré pasar de la versión beta a las siguientes? + +We're still working on a formal roadmap. We have a lot of plans and ideas, and look forward to sharing a more thorough milestone with the community. + +### ¿Puedo donar dinero para acelerar el desarrollo? + +Todas las donaciones son bienvenidas. Puedes donar en [Github Sponsors](https://github.com/sponsors/flarum) o en [OpenCollective](https://opencollective.com/flarum). + +Sin embargo, las donaciones no tendrán un impacto directo en la velocidad de desarrollo de Flarum. También animamos a los usuarios a contribuir de otras maneras, como [contribuyendo con código](contributing.md), [construyendo extensiones](/extend/), escribiendo documentación, traduciendo Flarum a otros idiomas, proporcionando ayuda y soporte en los [foros de la comunidad](https://discuss.flarum.org/)... + +### ¿Tendrá Flarum [insertar característica aquí]? When? ¿Cuándo? ¿Por qué no? + +Nos encantaría construir innumerables características y extensiones para Flarum, pero lo primero es lo primero: Nos centramos en lo esencial y en la estabilidad. + +### ¿Puedo integrar Flarum con WordPress/Laravel/etc.? + +También en este caso, la respuesta es "lo primero es lo primero". Si aún no hemos solucionado un problema (o no le hemos asignado un hito), es porque estamos trabajando en otra cosa igual de importante. Por favor, tened paciencia; intentaremos que esté listo antes del lanzamiento. O si tienes prisa, no dudes en arreglarlo tú mismo y [contribuir al proyecto](contributing.md). + +### ¿Podré migrar mi foro a Flarum? + +We don't currently provide official migrators, but there are many community solutions out there. Una vez que estemos seguros de que Flarum está listo para ser utilizado en la producción, vamos a empezar a construir herramientas para importar datos de otro software de foro como esoTalk, FluxBB, phpBB, Discourse, y otros. + +### ¿Por qué todavía no han arreglado [inserte el problema aquí]? + +> "A través de un arcano y arduo calvario, que implica rituales místicos, peligros que amenazan la vida y aventuras a tierras lejanas donde muchos van y pocos vuelven." ~ jordanjay29 + +La respuesta real es que, por lo general, echamos un ojo a nuestra comunidad en busca de miembros destacados que puedan ser un buen personal. Honestamente, para la mayoría de nuestro personal actual, lo que hacían antes de convertirse en personal no era muy diferente de lo que hacen ahora. + +Encuentra una pasión y contribuye de la manera que creas más conveniente. Luego deja que siga su curso. No hace falta tener una insignia para ser respetado aquí. \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/install.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/install.md new file mode 100644 index 000000000..999fc3478 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/install.md @@ -0,0 +1,198 @@ +# Instalación + +:::danger + +No dude en probar Flarum en uno de nuestros [foros de demostración](https://discuss.flarum.org/d/21101). O bien, configure su propio foro en segundos en [Free Flarum](https://www.freeflarum.com), un servicio comunitario gratuito no afiliado al equipo de Flarum. + +::: + +## Requisitos del Servidor + +Antes de instalar Flarum, es importante comprobar que tu servidor cumple los requisitos. Para ejecutar Flarum, necesitarás: + +* **Apache** (con mod\_rewrite activado) o **Nginx**. +* **PHP 7.3+** with the following extensions: curl, dom, fileinfo, gd, json, mbstring, openssl, pdo\_mysql, tokenizer, zip +* **MySQL 5.6+** o **MariaDB 10.0.5+** +* **SSH (command-line) access** to run potentially necessary software maintenance commands, and Composer if you intend on using the command-line to install and manage Flarum extensions. + +## Instalando + +### Installing by unpacking an archive + +If you don't have SSH access to your server or you prefer not to use the command line, you can install Flarum by unpacking an archive. Below is a list of the available archives, make sure you choose the one that matches your PHP version and public path or lack thereof preference. + +| Flarum Version | PHP Version | Public Path | Type | Archive | +| -------------- | ----------------- | ----------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1.x | 8.3 (recommended) | No | ZIP | [flarum-v1.x-no-public-dir-php8.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.3.zip) | +| 1.x | 8.3 (recommended) | Yes | TAR.GZ | [flarum-v1.x-php8.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.3.tar.gz) | +| 1.x | 8.3 (recommended) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.3.tar.gz) | +| 1.x | 8.3 (recommended) | Yes | ZIP | [flarum-v1.x-php8.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.3.zip) | +| 1.x | 8.2 (recommended) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.2.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.2.tar.gz) | +| 1.x | 8.2 (recommended) | Yes | TAR.GZ | [flarum-v1.x-php8.2.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.2.tar.gz) | +| 1.x | 8.2 (recommended) | No | ZIP | [flarum-v1.x-no-public-dir-php8.2.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.2.zip) | +| 1.x | 8.2 (recommended) | Yes | ZIP | [flarum-v1.x-php8.2.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.2.zip) | +| 1.x | 8.1 | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.1.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.1.tar.gz) | +| 1.x | 8.1 | Yes | TAR.GZ | [flarum-v1.x-php8.1.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.1.tar.gz) | +| 1.x | 8.1 | No | ZIP | [flarum-v1.x-no-public-dir-php8.1.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.1.zip) | +| 1.x | 8.1 | Yes | ZIP | [flarum-v1.x-php8.1.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.1.zip) | +| 1.x | 8.0 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.0.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.0.tar.gz) | +| 1.x | 8.0 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php8.0.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.0.tar.gz) | +| 1.x | 8.0 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php8.0.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.0.zip) | +| 1.x | 8.0 (end of life) | Yes | ZIP | [flarum-v1.x-php8.0.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.0.zip) | +| 1.x | 7.4 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php7.4.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.4.tar.gz) | +| 1.x | 7.4 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php7.4.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.4.tar.gz) | +| 1.x | 7.4 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php7.4.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.4.zip) | +| 1.x | 7.4 (end of life) | Yes | ZIP | [flarum-v1.x-php7.4.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.4.zip) | +| 1.x | 7.3 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php7.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.3.tar.gz) | +| 1.x | 7.3 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php7.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.3.tar.gz) | +| 1.x | 7.3 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php7.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.3.zip) | +| 1.x | 7.3 (end of life) | Yes | ZIP | [flarum-v1.x-php7.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.3.zip) | + +### Installing using the Command Line Interface + +Flarum utiliza [Composer](https://getcomposer.org) para gestionar sus dependencias y extensiones. Antes de instalar Flarum, necesitarás [instalar Composer](https://getcomposer.org) en tu máquina. Después, ejecuta este comando en una ubicación vacía en la que quieras que se instale Flarum: + +```bash +composer create-project flarum/flarum . +``` + +Mientras se ejecuta este comando, puede configurar su servidor web. Tendrás que asegurarte de que tu webroot está configurado en `/ruta/para/su/foro/public`, y configurar el [URL Rewriting](#url-rewriting) según las instrucciones siguientes. + +Cuando todo esté listo, navega a tu foro en un navegador web y sigue las instrucciones para completar la instalación. + +If you wish to install and update extensions from the admin dashboard, you need to also install the [Extension Manager](extensions.md) extension. + +```bash +composer require flarum/extension-manager:* +``` + +:::warning + +The extension manager allows an admin user to install any composer package. Only install the extension manager if you trust all of your forum admins with such permissions. + +::: + +## URL Rewriting + +### Apache + +Flarum incluye un archivo `.htaccess` en el directorio `public` - asegúrese de que ha sido descargado correctamente. **Flarum no funcionará correctamente si `mod_rewrite` no está habilitado o `.htaccess` no está permitido.** Asegúrate de comprobar con tu proveedor de hosting (o tu VPS) que estas características están habilitadas. Si gestionas tu propio servidor, puede que tengas que añadir lo siguiente a la configuración de tu sitio para habilitar los archivos `.htaccess`: + +``` + + AllowOverride All + +``` + +Esto asegura que las sobreescrituras de htaccess están permitidas para que Flarum pueda reescribir las URLs correctamente. + +Los métodos para habilitar `mod_rewrite` varían dependiendo de su sistema operativo. Puedes activarlo ejecutando `sudo a2enmod rewrite` en Ubuntu. En CentOS está activado por defecto. No te olvides de reiniciar Apache después de hacer las modificaciones. + +### Nginx + +Flarum incluye un archivo `.nginx.conf` - asegúrate de que se ha descargado correctamente. Entonces, asumiendo que tienes un sitio PHP configurado dentro de Nginx, añade lo siguiente al bloque de configuración de tu servidor: + +```nginx +include /ruta/para/flarum/.nginx.conf; +``` + +### Caddy + +Caddy requiere una configuración muy sencilla para que Flarum funcione correctamente. Tenga en cuenta que debe reemplazar la URL con la suya propia y la ruta con la ruta a su propia carpeta `public`. Si está usando una versión diferente de PHP, también necesitará cambiar la ruta `fastcgi` para que apunte a su socket o URL de instalación de PHP correcta. + +``` +www.example.com { + root * /var/www/flarum/public + php_fastcgi unix//var/run/php/php7.4-fpm.sock + header /assets/* { + +Cache-Control "public, must-revalidate, proxy-revalidate" + +Cache-Control "max-age=25000" + Pragma "public" + } + file_server +} +``` +## Propiedad de la Carpeta + +Durante la instalación, Flarum puede solicitar que se permita la escritura en ciertos directorios. Modern operating systems are generally multi-user, meaning that the user you log in as is not the same as the user Flarum is running as. The user that Flarum is running as MUST have read + write access to: + +- The root install directory, so Flarum can edit `config.php`. +- The `storage` subdirectory, so Flarum can edit logs and store cached data. +- The `assets` subdirectory, so that logos and avatars can be uploaded to the filesystem. + +Extensions might require other directories, so you might want to recursively grant write access to the entire Flarum root install directory. + +There are several commands you'll need to run in order to set up file permissions. Please note that if your install doesn't show warnings after executing just some of these, you don't need to run the rest. + +First, you'll need to allow write access to the directory. On Linux: + +```bash +chmod 775 -R /path/to/directory +``` + +If that isn't enough, you may need to check that your files are owned by the correct group and user. By default, in most Linux distributions `www-data` is the group and user that both PHP and the web server operate under. You'll need to look into the specifics of your distro and web server setup to make sure. You can change the folder ownership in most Linux operating systems by running: + +```bash +chown -R www-data:www-data /path/to/directory +``` + +With `www-data` changed to something else if a different user/group is used for your web server. + +Additionally, you'll need to ensure that your CLI user (the one you're logged into the terminal as) has ownership, so that you can install extensions and manage the Flarum installation via CLI. To do this, add your current user (`whoami`) to the web server group (usually `www-data`) via `usermod -a -G www-data YOUR_USERNAME`. You will likely need to log out and back in for this change to take effect. + +Finally, if that doesn't work, you might need to configure [SELinux](https://www.redhat.com/en/topics/linux/what-is-selinux) to allow the web server to write to the directory. To do so, run: + +```bash +chcon -R -t httpd_sys_rw_content_t /path/to/directory +``` + +To find out more about these commands as well as file permissions and ownership on Linux, read [this tutorial](https://www.thegeekdiary.com/understanding-basic-file-permissions-and-ownership-in-linux/). If you are setting up Flarum on Windows, you may find the answers to [this Super User question](https://superuser.com/questions/106181/equivalent-of-chmod-to-change-file-permissions-in-windows) useful. + +:::caution Environments may vary + +Your environment may vary from the documentation provided, please consult your web server configuration or web hosting provider for the proper user and group that PHP and the web server operate under. + +::: + +:::danger Never use permission 777 + +You should never set any folder or file to permission level `777`, as this permission level allows anyone to access the content of the folder and file regardless of user or group. + +::: + +## Personalización de las Rutas + +By default Flarum's directory structure includes a `public` directory which contains only publicly-accessible files. This is a security best-practice, ensuring that all sensitive source code files are completely inaccessible from the web root. + +However, if you wish to host Flarum in a subdirectory (like `yoursite.com/forum`), or if your host doesn't give you control over your webroot (you're stuck with something like `public_html` or `htdocs`), you can set up Flarum without the `public` directory. + +If you intend to install Flarum using one of the archives, you can simply use the `no-public-dir` (Public Path = No) [archives](#installing-by-unpacking-an-archive) and skip the rest of this section. If you're installing via Composer, you'll need to follow the instructions below. + +Simply move all the files inside the `public` directory (including `.htaccess`) into the directory you want to serve Flarum from. Then edit `.htaccess` and uncomment lines 9-15 in order to protect sensitive resources. For Nginx, uncomment lines 8-11 of `.nginx.conf`. + +You will also need to edit the `index.php` file and change the following line: + +```php +$site = require './site.php'; +``` + + Edit the `site.php` and update the paths in the following lines to reflect your new directory structure: + +```php +'base' => __DIR__, +'public' => __DIR__, +'storage' => __DIR__.'/storage', +``` + +Finally, check `config.php` and make sure the `url` value is correct. + +## Importar datos + +If you have an existing community and don't want to start from scratch, you may be able to import your existing data into Flarum. While there are no official importers yet, the community has made several unofficial importers: + +* [FluxBB](https://discuss.flarum.org/d/3867-fluxbb-to-flarum-migration-tool) +* [MyBB](https://discuss.flarum.org/d/5506-mybb-migrate-script) +* [phpBB](https://discuss.flarum.org/d/1117-phpbb-migrate-script-updated-for-beta-5) +* [SMF2](https://github.com/ItalianSpaceAstronauticsAssociation/smf2_to_flarum) + +These can be used for other forum software as well by migrating to phpBB first, then to Flarum. Be aware that we can't guarantee that these will work nor can we offer support for them. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/README.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/README.md new file mode 100644 index 000000000..ff153a3bc --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/README.md @@ -0,0 +1,7 @@ +--- +slug: '/internal' +--- + +# Internal Team Docs + +This is a new documentation section, where we will be posting some docs used internally by the Flarum team. We are starting this section to provide our community with transparency as to how Flarum is run, and to help those hoping to contribute to Flarum. \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md new file mode 100644 index 000000000..555e7977c --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md @@ -0,0 +1,28 @@ +# Bundled Extensions Policy + +This document is to assist in deciding what core features should be bundled or maintained by the Flarum project team. + +Understand that Flarum aims to have a lean and efficient team. To guarantee a transparent workload, we intentionally have a "this could be an extension" mentality. The acronym D.O.R.C. spells out our decision-making process. + +- **Density**: prevent bloating Flarum so that it becomes a burden to install on shared hosting plans with limited space. +- **Opinionatedness**: no extensions should be bundled that is only useful by only a limited amount of communities or on specific hosting environments. +- **Responsibility**: extensions that could easily be maintained by others should be maintained by others. +- **Complexity**: extensions that are complex in terms of design, frontend or backend code should not be a responsibility of the Flarum project team. + +### Density + +To prevent the installation size of Flarum from continuously increasing we need to protect it from extensions that bloat it. We should ship extensions with Flarum that, for instance, have kilobytes in media files. + +### Opinionatedness + +Our goal is to allow installation of Flarum, in its vanilla form, by any community on any hosting environment. This includes shared hosting environment as well. + +Releasing Flarum with extensions that add functionality specific to cloud based (AWS) installations or for corporate support communities, as such, is unwanted. + +### Responsibility + +Protecting the time of the project team is key. To do so we should empower the ecosystem in building extensions that it needs. Therefor we distance ourselves from the responsibility of building every and all extensions. The responsibility of extension development is held primarily by our community. + +### Complexity + +Complex extensions require a vast amount of time, not just for development, but also documentation and support. To protect the lean and efficient principles of the team, we will not take ownership of extensions that add this complexity. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md new file mode 100644 index 000000000..c6ef1c890 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md @@ -0,0 +1,87 @@ +# Extension Manager +This contains an explanation of how the extension manager works and what it has to offer. + +slightly outdated: see [the extensions guide for more](/extensions.md). + +## Contents +* Installing, Updating, and Removing Extensions. +* [Checking for Updates](#checking-for-updates). +* [Global Flarum Update](#global-flarum-updates). +* [Patch-Minor Flarum Updates](#patch-minor-flarum-updates). +* [Major Flarum Update](#major-flarum-updates). +* [Flarum Updates (global, minor, major)](#flarum-updates-global-minor-major). +* [Background Tasks](#background-tasks). + +## Requirements +There are some obstacles that need to be taken care of before this can be used. + +### File Permissions +The relevant machine web user needs to have permissions to read and write to: `vendor`, `composer.json`, `composer.lock` and `storage`. Right now a warning shows up when this is not the case, this should preferably be changed to mention only the files/dirs where permissions are lacking instead of all of them. + +![flarum lan_admin (3)](https://user-images.githubusercontent.com/20267363/135268536-f79d42ab-6e05-4e41-b2ab-d95ec7a8b021.png) + +### Path Repository +In development environments (and production in rare scenarios) there should a path repository to a directory containing (mostly dev) packages, the path to this directory must be changed to an absolute path otherwise composer will have trouble running any command. Additionally the path repository by default has higher priority, so requiring an extension that exists in that repository will probably fail, unless a `*@dev` constraint is specified, in which case the extension manager should not be used for dev purposes anyway. + +There is currently now hint of any of this in the extension manager UI. + +## Common Actions +Each one of the features listed above is basically a composer command or two, and there are common actions/common behaviour between them all. + +* Restricting access to the admin. +* Validating the provided package name or the extension id if given. +* Erroring out if installing an existing extension, updating or removing a non existing extension ...etc +* Running the command. This [auto logs the output](#command-output-logging). +* [Erroring out on command failure](#command-failure). +* Dispatching an event. +* If running an update: + + Clear Cache. + + Run Migrations. + + Publish Assets. + + Run an update check, and log any extensions that didn't update to their latest versions in the update process. + +### Command Output Logging +Considering this is still experimental and especially for the sake of easier support, each command output is logged to `storage/logs/composer` just like the flarum error logs, allowing to go back and see what happened during a command execution. + +### Command Failure +When a composer command fails (recognised by the exit code), an exception is thrown containing a reason guessed by the exception based on the command output text. Guessed causes render into proper explanatory alert messages on the frontend. + +## Checking for Updates +This executes the command `composer outdated -D --format json` which checks for updates of packages directly required in the root `composer.json` and outputs the results in JSON format. Only packages marked as `semver-safe-update` and `update-possible` by composer are displayed. + +The information about the last update check is saved into a JSON setting. + +![flarum lan_admin (4)](https://user-images.githubusercontent.com/20267363/135272032-9de37599-b364-4e42-b234-1113135eaa83.png) + +## Global Flarum Updates +Simply runs the command `command update --prefer-dist --no-dev -a --with-all-dependencies`, useful for updating all packages. + +## Patch-Minor Flarum Updates +This changes directly required package versions to `*` and then executes the command `command update --prefer-dist --no-dev -a --with-all-dependencies`. + +![flarum lan_admin (5)](https://user-images.githubusercontent.com/20267363/135276114-ae438c2f-4122-45bd-b32f-690de3b56e25.png) + +## Major Flarum Updates +This changes directly required package versions to `*`, changes core to the latest major version requirement and then executes the same command above. Upon failure, it can be correctly guessed that some extensions are not compatible with the new major version, the exception details will include an array of extension package names that are not compatible, and it'll be rendered in the frontend, with the ability to run a `composer why-not flarum/core 2.0` for more details. + +![major update UI](https://user-images.githubusercontent.com/20267363/143277865-8323fa9a-c80f-4015-baca-fce4d2b5d585.png) + +## Flarum Updates (global, minor, major) +Information about the last updates ran are saved in a `last_update_run` JSON setting, which can contain an array of extension package names that didn't update to their latest version in the process, this is rendered in the frontend as warning icon buttons on the extension items, clicking on them will execute a `composer why-not`, displaying the details of the failure in a modal. + +![UI with list of extensions containing warning icon buttons](https://user-images.githubusercontent.com/20267363/143278774-6fada0da-dead-474b-8dfa-feda5021134f.png) ![UI with the modal showing the details](https://user-images.githubusercontent.com/20267363/143278786-d283db62-de96-4019-954e-932d0d6eac15.png) + +## Background Tasks +To get around timeout issues, composer commands can also run on the background use the queue. Users can be pointed towards [Blomstra's Database Queue Implementation](https://discuss.flarum.org/d/28151-database-queue-the-simplest-queue-even-for-shared-hosting) as a basic queue solution. It contains instructions on how to enable the queue through a cron job. + +:::danger Cron Job PHP Process Version + +It is common for shared hosts to have a low php version used in SSH, users must be pointed to the fact that they have to make sure the php process is of a version compatible with Flarum. Either by manually checking or by asking their hosts. + +::: + +![Extension Manager Queue Table Preview](/en/img/extension-manager-queue.png) + +## TODO +- Try on shared hosting. +- Better explanation on the UI about background tasks. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md new file mode 100644 index 000000000..067e2809f --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md @@ -0,0 +1,38 @@ +# PR Merging Policy + +Technical contributions to the Flarum source code go through a review process. Over the years we have tuned this process based on our experiences, our targeted development speed and availability. + +## What makes a great Pull Request? + +Great pull requests: + +- Have the [Pull Request template](https://github.com/flarum/.github/blob/main/PULL_REQUEST_TEMPLATE.md) filled out completely when opening a pull request. +- Do not combine different changes. Although tempting, don't change formatting of unrelated code. Stick to the one feature or change you wish to contribute. +- Have a related issue where the technical implementation has been agreed upon by the core team, or has been approved on by the core team through discussion on the official forums or other channels like Discord. +- Clearly explain the need for the change and list the areas where the pull request requires discussion. + +## Implementation Review Criteria + +- Adheres to our conventions or can be patched up easily after merging, follows proper code style. +- Are there any implementation details that could be done better through alternate technologies/technical approaches? +- Does not touch any lines outside of the intended changes, eg through formatting or compilation. +- If the changes are to code intended as a public API, has a proper doc block been included? + +## Merge Time! + +If all the checks in the template are met, **any** core developer may merge this PR. If the PR is authored by a core developer, they should probably be the ones to merge it. + +- Merging: + - GitHub offers several ways to merge a PR. Choose between the following strategies: + - **Merge** when the PR branch consists of atomic, well-described commits that are nice to have in the version history. + - **Squash** when lots of cleanup commits have accumulated. Please make sure to follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) spec for the squash commit. We usually find several commits from bots like StyleCI in these prefabricated commit messages, their commit messages should be removed. + +- After merging: + - Assign the related issue (if none exists, the pull request itself, but never both) to the appropriate milestone. + - Close all relevant issues (*if* they are closed completely). + - Regressions should be labeled as such and removed from the project board and milestone after merging. + - Check for follow-up tasks: + - Merge related PRs (language files, extensions, documentations). + - Documentation updates. + - Create issues for further follow-up tasks, if necessary. + diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/merging.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/merging.md new file mode 100644 index 000000000..0408b1bee --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/merging.md @@ -0,0 +1,29 @@ +# PR Merging Workflow + + +## Implementation Review Criteria + +- Adheres to our conventions or can be patched up easily after merging, follows proper code style. +- Are there any implementation details that could be done better through alternate technologies/technical approaches? +- Does not touch any lines outside of the intended changes, eg through formatting or compilation. +- If the changes are to code intended as a public API, has a proper doc block been included? + +## Merge Time! + +If all of the checks in the template are met, **any** core developer may merge this PR. If the PR is authored by a core developer, they should probably be the ones to merge it. + +- Merging: + - GitHub offers several ways to merge a PR. Choose between the following strategies: + - **Merge** when the PR branch consists of atomic, well-described commits that are nice to have in the version history. + - **Squash** when lots of cleanup commits have accumulated. Please make sure to follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) spec for the squash commit. + +- After merging: + - Make sure the *issue* (if none exists, the PR - but not both) belongs to the appropriate milestone and project board. + - PRs in extensions cannot be assigned to core milestones, so create a core issue that references it and add it to the milestone. + - Close all relevant issues (*if* they are closed completely). + - Regressions should be labeled as such and removed from the project board and milestone after merging. + - Check for follow-up tasks: + - Merge related PRs (language files, extensions, documentations). + - Documentation updates. + - Create issues for further follow-up tasks, if necessary. + diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md new file mode 100644 index 000000000..823599db5 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md @@ -0,0 +1,89 @@ +# Package Manager +This contains an explanation of how the package manager works and what it has to offer. + +## Contents +* Installing, Updating, and Removing Extensions. +* [Checking for Updates](#checking-for-updates). +* [Global Flarum Update](#global-flarum-updates). +* [Patch-Minor Flarum Updates](#patch-minor-flarum-updates). +* [Major Flarum Update](#major-flarum-updates). +* [Flarum Updates (global, minor, major)](#flarum-updates-global-minor-major). +* [Background Tasks](#background-tasks). + +## Requirements +There are some obstacles that need to be taken care of before this can be used. + +### File Permissions +The relevant machine web user needs to have permissions to read and write to: `vendor`, `composer.json`, `composer.lock` and `storage`. Right now a warning shows up when this is not the case, this should preferably be changed to mention only the files/dirs where permissions are lacking instead of all of them. + +![flarum lan_admin (3)](https://user-images.githubusercontent.com/20267363/135268536-f79d42ab-6e05-4e41-b2ab-d95ec7a8b021.png) + +### Path Repository +In development environments (and production in rare scenarios) there should a path repository to a directory containing (mostly dev) packages, the path to this directory must be changed to an absolute path otherwise composer will have trouble running any command. Additionally the path repository by default has higher priority, so requiring an extension that exists in that repository will probably fail, unless a `*@dev` constraint is specified, in which case the package manager should not be used for dev purposes anyway. + +There is currently now hint of any of this in the package manager UI. + +## Common Actions +Each one of the features listed above is basically a composer command or two, and there are common actions/common behaviour between them all. + +* Restricting access to the admin. +* Validating the provided package name or the extension id if given. +* Erroring out if installing an existing extension, updating or removing a non existing extension ...etc +* Running the command. This [auto logs the output](#command-output-logging). +* [Erroring out on command failure](#command-failure). +* Dispatching an event. +* If running an update: + + Clear Cache. + + Run Migrations. + + Publish Assets. + + Run an update check, and log any extensions that didn't update to their latest versions in the update process. + +### Command Output Logging +Considering this is still experimental and especially for the sake of easier support, each command output is logged to `storage/logs/composer` just like the flarum error logs, allowing to go back and see what happened during a command execution. + +### Command Failure +When a composer command fails (recognised by the exit code), an exception is thrown containing a reason guessed by the exception based on the command output text. Guessed causes render into proper explanatory alert messages on the frontend. + +## Checking for Updates +This executes the command `composer outdated -D --format json` which checks for updates of packages directly required in the root `composer.json` and outputs the results in JSON format. Only packages marked as `semver-safe-update` and `update-possible` by composer are displayed. + +The information about the last update check is saved into a JSON setting. + +![flarum lan_admin (4)](https://user-images.githubusercontent.com/20267363/135272032-9de37599-b364-4e42-b234-1113135eaa83.png) + +## Global Flarum Updates +Simply runs the command `command update --prefer-dist --no-dev -a --with-all-dependencies`, useful for updating all packages. + +## Patch-Minor Flarum Updates +This changes directly required package versions to `*` and then executes the command `command update --prefer-dist --no-dev -a --with-all-dependencies`. + +![flarum lan_admin (5)](https://user-images.githubusercontent.com/20267363/135276114-ae438c2f-4122-45bd-b32f-690de3b56e25.png) + +## Major Flarum Updates +This changes directly required package versions to `*`, changes core to the latest major version requirement and then executes the same command above. Upon failure, it can be correctly guessed that some extensions are not compatible with the new major version, the exception details will include an array of extension package names that are not compatible, and it'll be rendered in the frontend, with the ability to run a `composer why-not flarum/core 2.0` for more details. + +![major update UI](https://user-images.githubusercontent.com/20267363/143277865-8323fa9a-c80f-4015-baca-fce4d2b5d585.png) + +## Flarum Updates (global, minor, major) +Information about the last updates ran are saved in a `last_update_run` JSON setting, which can contain an array of extension package names that didn't update to their latest version in the process, this is rendered in the frontend as warning icon buttons on the extension items, clicking on them will execute a `composer why-not`, displaying the details of the failure in a modal. + +![UI with list of extensions containing warning icon buttons](https://user-images.githubusercontent.com/20267363/143278774-6fada0da-dead-474b-8dfa-feda5021134f.png) ![UI with the modal showing the details](https://user-images.githubusercontent.com/20267363/143278786-d283db62-de96-4019-954e-932d0d6eac15.png) + +## Background Tasks +To get around timeout issues, composer commands can also run on the background use the queue. Users can be pointed towards [Blomstra's Database Queue Implementation](https://discuss.flarum.org/d/28151-database-queue-the-simplest-queue-even-for-shared-hosting) as a basic queue solution. It contains instructions on how to enable the queue through a cron job. + +:::danger Cron Job PHP Process Version + +It is common for shared hosts to have a low php version used in SSH, users must be pointed to the fact that they have to make sure the php process is of a version compatible with Flarum. Either by manually checking or by asking their hosts. + +::: + +![Package Manager Queue Table Preview](/en/img/package-manager-queue.png) + +## TODO +- Try on shared hosting. +- Composer command job must not overlap. +- Code TODOs. +- Better explanation on the UI about background tasks. +- Take into consideration a scenario where we're updating an extension that isn't a root required dependency, like bundles. +- Run one background task at a time, prevent user from triggering multiple tasks. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/languages.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/languages.md new file mode 100644 index 000000000..def0ea989 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/languages.md @@ -0,0 +1,29 @@ +# Idiomas + +Es fácil añadir un nuevo idioma a tu instalación básica de Flarum. Sólo tienes que seguir las siguientes instrucciones para descargar e instalar el paquete de idioma de tu elección. + +Una vez que hayas añadido un paquete de idioma, puedes [establecerlo como idioma por defecto](#setting-the-default-language) para tu foro. Y si alguna vez descubres que no necesitas uno de los paquetes de idiomas instalados, siempre puedes [desactivarlo](#disabling-a-language-pack). Si usas extensiones de terceros, asegúrate de [leer esto](#extensiones-de-terceros) antes de empezar. + +## Instalación del paquete de idioma + +Para empezar, visite la etiqueta [Extensiones > Idiomas](https://discuss.flarum.org/t/languages) en el sitio de la Comunidad Flarum y encuentre un paquete de idioma que desee instalar. + +Los paquetes de idiomas se instalan de la misma manera que las [extensiones](extensions.md). El idioma aparecerá en la página de **Extensiones** de la interfaz de administración y podrás activarlo allí. + +Eso es todo. Ahora debería poder utilizar el selector de idioma en la cabecera de su sitio para cambiar la visualización de su foro al nuevo idioma. + +## Establecer el idioma por defecto + +Una vez que haya instalado un paquete de idioma y se haya asegurado de que funciona, es posible que quiera establecerlo como idioma por defecto para los nuevos usuarios e invitados. Puedes hacerlo en la página **Básicos** de la interfaz de administración. + +## Desactivar un Paquete de Idioma + +Si decides que no necesitas dar soporte a un determinado idioma, después de todo, puedes desactivarlo. Simplemente localice el paquete de idiomas en la página **Extensiones** de la interfaz de administración y desactívelo. + +Desactivar un idioma puede ser útil si tienes un sitio monolingüe y no quieres que el selector de idioma aparezca en la cabecera del sitio. El selector de idioma se oculta cuando sólo está habilitado un idioma. + +## Extensiones de la Comunidad + +Mientras que los paquetes de idiomas descargados desde el sitio de la Comunidad Flarum generalmente incluirán traducciones para todas las extensiones que vienen incluidas en Flarum, _no_ por regla general cubrirán cualquier extensión de la comunidad que pueda tener instalada. Es responsabilidad de los desarrolladores proporcionar y mantener las traducciones de sus extensiones. + +Por lo tanto, antes de instalar una extensión comunitaria, debe comprobar que incluye traducciones para cada paquete de idiomas que haya instalado. Si descubre que una extensión no es compatible con un idioma que usted necesita, póngase en contacto directamente con el desarrollador para que le añada las traducciones necesarias. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/mail.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/mail.md new file mode 100644 index 000000000..f96f2a778 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/mail.md @@ -0,0 +1,29 @@ +# Configuración del Correo Electrónico + +Cualquier comunidad necesita enviar correos electrónicos para permitir la verificación del correo electrónico, el restablecimiento de la contraseña, las notificaciones y otras comunicaciones a los usuarios. Configurar tu foro para enviar correos electrónicos debería ser uno de tus primeros pasos como administrador: una configuración incorrecta causará errores cuando los usuarios intenten registrarse. + +## Controladores Disponibles + +Flarum proporciona varios controladores por defecto, están listados y explicados a continuación. Los desarrolladores también pueden añadir [controladores de correo personalizados a través de extensiones](extend/mail.md). + +### SMTP + +Este es probablemente el controlador de correo electrónico más comúnmente utilizado, permitiéndole configurar un host, puerto/encriptación, nombre de usuario y contraseña para un servicio SMTP externo. Tenga en cuenta que el campo de encriptación espera `ssl` o `tls`. + +### Mail + +El controlador `mail` intentará utilizar el sistema de correo electrónico sendmail / postfix incluido en muchos servidores de alojamiento. Debe instalar y configurar correctamente sendmail en su servidor para que esto funcione. + +### Mailgun + +Este controlador utiliza su cuenta [Mailgun](https://www.mailgun.com/) para enviar correos electrónicos. Necesitarás una clave secreta, así como el dominio y la región de tu configuración de mailgun. + +To use the mailgun driver, you'll need to install the Guzzle composer package (a PHP HTTP client). You can do this by running `composer require guzzlehttp/guzzle:^6.0|^7.0` in your Flarum install's root directory. + +### Log + +The log mail driver DOES NOT SEND MAIL, and is primarily used by developers. It writes the content of any emails to the log file in `FLARUM_ROOT_DIRECTORY/storage/logs`. + +## Probar el Correo Electrónico + +Una vez que hayas guardado una configuración de correo electrónico, puedes hacer clic en el botón "Enviar correo de prueba" en la página de correo del panel de administración para asegurarte de que tu configuración funciona. Si ves un error o no recibes un correo electrónico, ajusta la configuración e inténtalo de nuevo. Asegúrate de revisar tu correo no deseado si no hay ningún error, pero no aparece nada en tu bandeja de entrada. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/releases.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/releases.md new file mode 100644 index 000000000..d9359b84e --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/releases.md @@ -0,0 +1,15 @@ +# Notas de la versión + + + + +Las notas de la versión se pueden encontrar en la [Comunidad de Flarum](https://discuss.flarum.org/t/blog?sort=newest). diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/rest-api.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/rest-api.md new file mode 100644 index 000000000..7e91238d3 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/rest-api.md @@ -0,0 +1,375 @@ +# Consuming the REST API + +Flarum exposes a REST API which is used by the single page application but also available for external scripts. + +The API follows the best practices defined by the [JSON:API](https://jsonapi.org/) specification. + +:::info + +To extend the REST API with new endpoints, see [API and Data Flow](extend/api.md) in the developer documentation. + +::: + +## Authentication + +The single page app uses session cookies to authenticate against the API. External scripts can use stateless authentication using [API Keys](#api-keys) or [Access Tokens](#access-tokens). + +`GET` endpoints can be used without authentication. Only content visible to guests will be returned. Other endpoints generally cannot be used without authentication because of the [CSRF protection](#csrf-protection). + +### API keys + +API Keys are the primary way for scripts, tools and integrations to interact with Flarum. + +#### Creation + +There is currently no UI to manage API Keys, but they can be created manually in the `api_keys` table of the database. + +The following attributes can be filled: + +- `key`: Generate a long unique token (recommended: alpha-numerical, 40 characters) and set it here, this will be the token used in the `Authorization` header. +- `user_id`: Optional. If set, the key can only be used to act as the given user. + +The remaining attributes are either automatically filled or currently not used: + +- `id`: Will be filled by MySQL auto-increment. +- `allowed_ips`: Not implemented. +- `scopes`: Not implemented. +- `created_at`: Can be set to any date, but is meant for the date of creation of the key. +- `last_activity_at`: Will be updated automatically when the token is used. + +#### Usage + +Attach your key value to each API request using the `Authorization` header. Then provide the user ID you want to interact as at the end of the header: + + Authorization: Token YOUR_API_KEY_VALUE; userId=1 + +If a `user_id` value has been set for the key in the database, `userId=` will be ignored. Otherwise, it can be set to any valid user ID that exists in the database. + +### Access Tokens + +Access Tokens are short-lived tokens that belong to a specific user. + +Those tokens are used behind the scenes for cookie sessions. Their use in stateless API requests has the same effect as a regular session. The user last activity will be updated each time the token is used. + +#### Creation + +All users are allowed to create access tokens. To create a token, use the `/api/token` endpoint with the credentials of your user: + +``` +POST /api/token HTTP/1.1 + +{ + "identification": "Toby", + "password": "pass7word" +} + +HTTP/1.1 200 OK + +{ + "token": "YACub2KLfe8mfmHPcUKtt6t2SMJOGPXnZbqhc3nX", + "userId": "1" +} +``` + +At the moment, 3 token types exist, although only 2 types can be created via the REST API. + +- `session` tokens expire after 1h of inactivity. This is the default token type. +- `session_remember` tokens expire after 5 years of inactivity. They can be obtained by specifying `remember=1` in the request attributes. +- `developer` tokens never expire. They can only be created manually in the database at the moment. + +**All access tokens are deleted when the user logs out** (this includes `developer` tokens, although it is planned to change it). + +#### Usage + +Attach the returned `token` value to each API request using the `Authorization` header: + + Authorization: Token YACub2KLfe8mfmHPcUKtt6t2SMJOGPXnZbqhc3nX + +### CSRF Protection + +Most of the `POST`/`PUT`/`DELETE` API endpoints are protected against [Cross-site request forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery). This means stateless requests are not possible without authentication. + +When using an API Key or Access Token, CSRF protection is bypassed. + +## Endpoints + +This part of the documentation is still in progress. We are researching options to provide an automated documentation of the endpoints. + +Every extension adds new endpoints and attributes so it's difficult to provide a complete documentation of all endpoints. A good way to discover endpoints is to use the browser development tools to inspect requests made by the single page application. + +Below are a few examples of commonly used endpoints. JSON has been truncated to make reading easier. + +### List discussions + + GET /api/discussions + +```json +{ + "links": { + "first": "https://flarum.tld/api/discussions", + "next": "https://flarum.tld/api/discussions?page%5Boffset%5D=20" + }, + "data": [ + { + "type": "discussions", + "id": "234", + "attributes": { + "title": "Lorem Ipsum", + "slug": "234-lorem-ipsum", + "commentCount": 10, + "participantCount": 3, + "createdAt": "2022-01-01T10:20:30+00:00", + "lastPostedAt": "2022-01-05T10:20:30+00:00", + "lastPostNumber": 10, + "canReply": true, + "canRename": true, + "canDelete": true, + "canHide": true, + "isHidden": true, + "hiddenAt": "2022-01-06T10:20:30+00:00", + "lastReadAt": "2022-01-02T10:20:30+00:00", + "lastReadPostNumber": 2, + "isApproved": true, + "canTag": true, + "isLocked": false, + "canLock": true, + "isSticky": false, + "canSticky": true, + "canMerge": true, + "subscription": null + }, + "relationships": { + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + "lastPostedUser": { + "data": { + "type": "users", + "id": "64" + } + }, + "tags": { + "data": [ + { + "type": "tags", + "id": "3" + } + ] + }, + "firstPost": { + "data": { + "type": "posts", + "id": "668" + } + } + } + }, + { + "type": "discussions", + "id": "234", + "attributes": { + // [...] + }, + "relationships": { + // [...] + } + }, + // [...] more discussions + ], + "included": [ + { + "type": "users", + "id": "1", + "attributes": { + "username": "Admin", + "displayName": "Admin", + "avatarUrl": null, + "slug": "1" + } + }, + { + "type": "users", + "id": "64", + "attributes": { + "username": "Flarum", + "displayName": "Flarum", + "avatarUrl": "https://flarum.tld/assets/avatars/Z4hEncw0ndVqZ8be.png", + "slug": "64" + } + }, + { + "type": "tags", + "id": "3", + "attributes": { + "name": "Welcome", + "description": "Post interesting things here", + "slug": "welcome", + "color": "#888", + "backgroundUrl": null, + "backgroundMode": null, + "icon": "fas fa-bullhorn", + "discussionCount": 30, + "position": 1, + "defaultSort": null, + "isChild": false, + "isHidden": false, + "lastPostedAt": "2022-01-05T10:20:30+00:00", + "canStartDiscussion": true, + "canAddToDiscussion": true, + "isRestricted": false + } + }, + { + "type": "posts", + "id": "668", + "attributes": { + "number": 1, + "createdAt": "2022-01-01T10:20:30+00:00", + "contentType": "comment", + "contentHtml": "

Hello World

" + } + }, + // [...] more includes for the other discussions + ] +} +``` + +### Create discussion + + POST /api/discussions + +```json +{ + "data":{ + "type": "discussions", + "attributes": { + "title": "Lorem Ipsum", + "content": "Hello World" + }, + "relationships": { + "tags": { + "data": [ + { + "type": "tags", + "id": "1" + } + ] + } + } + } +} +``` + +The response includes the ID of the new discussion: + +```json +{ + "data": { + "type": "discussions", + "id": "42", + "attributes": { + "title": "Lorem Ipsum", + "slug": "42-lorem-ipsum", + "commentCount": 1 + // [...] other attributes + }, + "relationships": { + "posts": { + "data": [ + { + "type": "posts", + "id": "58" + } + ] + }, + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + // [...] other relationships + } + }, + "included":[ + { + "type": "posts", + "id": "38", + "attributes": { + "number": 1, + "contentType": "comment", + "contentHtml": "\u003Cp\u003EHello World\u003C\/p\u003E" + // [...] other attributes + } + } + // [...] other includes + ] +} +``` + +### Create user + + POST /api/users + +```json +{ + "data": { + "attributes": { + "username": "Flarum", + "email": "flarum@example.com", + "password": "correcthorsebatterystaple" + } + } +} +``` + +## Errors + +Flarum uses various HTTP status code and includes error descriptions that follow the [JSON:API error spec](https://jsonapi.org/format/#errors). + +Below are a few common errors you might encounter when using the REST API: + +### CSRF Token Mismatch + +If you receive a 400 HTTP error with `csrf_token_mismatch` message, it means the `Authorization` header is absent or invalid and Flarum attempted to authenticate through the session cookie. + +```json +{ + "errors": [ + { + "status": "400", + "code": "csrf_token_mismatch" + } + ] +} +``` + +### Validation errors + +Validation errors are returned with 422 HTTP status code. The name of the invalid field is returned as the `pointer` value. There can be multiple errors for a single field at the same time. + +```json +{ + "errors": [ + { + "status": "422", + "code": "validation_error", + "detail": "The username has already been taken.", + "source":{ + "pointer":"\/data\/attributes\/username" + } + }, + { + "status": "422", + "code": "validation_error", + "detail": "The email has already been taken.", + "source": { + "pointer":"\/data\/attributes\/email" + } + } + ] +} +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/scheduler.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/scheduler.md new file mode 100644 index 000000000..6123ce7c3 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/scheduler.md @@ -0,0 +1,55 @@ +# Scheduler + +The Flarum scheduler allows extensions to automate certain tasks effortlessly. In this guide we will see how to set it up. We won't go into the details of cron itself, but if you want to read more about it, I suggest you take a look at [this Wikipedia article](https://en.wikipedia.org/wiki/Cron) on cron. + +## Why should I care? + +Quite simply, a growing list of extensions now support handling certain functions automatically for you, completely behind the scenes. Wondering why `fof/drafts` 'scheduled drafts' are not posting, or `fof/best-answer` 'remind users to set a best answer after X days' does not fire? That'll be because they will setup themselves with the scheduler service, but without a one-liner cron job, nothing will happen! + +## What extensions currently use the scheduler? + +Some of the most popular examples are the following: + +- [FoF Best Answer](https://github.com/FriendsOfFlarum/best-answer) +- [FoF Drafts](https://github.com/FriendsOfFlarum/drafts) +- [FoF Sitemap](https://github.com/FriendsOfFlarum/sitemap) +- [FoF Open Collective](https://github.com/FriendsOfFlarum/open-collective) +- [FoF Github Sponsors](https://github.com/FriendsOfFlarum/github-sponsors) + +## Ok, let's get this setup! + +Most (if not all) Linux distros either come with, or can have, cron installed. For example, on Debian and Ubuntu based systems, you can install `cron` like this: + +``` +sudo apt-get update +sudo apt-get install cron +``` + +In case you are using a RHEL based Linux distribution (CentOS, AlmaLinux, Rocky Linux...), install cron like this: + +``` +sudo dnf update +sudo dnf install crontabs +``` + +Once you have cron installed, let's create the one and only entry you need for Flarum: + +``` +crontab -e +``` + +This will open the cron editor. You may or may not have other entries there. Add this line, and remember to leave an empty line at the bottom. + +``` +* * * * * cd /path-to-your-project && php flarum schedule:run >> /dev/null 2>&1 +``` + +`* * * * *` tells cron to run your command every minute. + +In case you want to use a different value and don't know exactly how cron expressions work, you can use a [cron expression generator](https://crontab.guru) to easily get the desired string. + +`cd /path-to-your-project && php flarum schedule:run` executes Flarum's scheduler to trigger any tasks currently waiting to be run. If PHP isn't in your system's path, you may need to experiment with setting the full path to PHP. + +Lastly `>> /dev/null 2>&1` suppresses any output from the command. + +Voila! Now any extension that registers a task to run, anything from every minute to daily, monthly, yearly - whatever - will now run on your server. diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/themes.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/themes.md new file mode 100644 index 000000000..6900853ca --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/themes.md @@ -0,0 +1,29 @@ +# Theming + +While we've worked hard to make Flarum as beautiful as we can, each community will probably want to make some tweaks/modifications to fit their desired style. + +## Panel de Administración + +The [admin dashboard](admin.md)'s Appearance page is a great first place to start customizing your forum. Here, you can: + +- Select theme colors +- Toggle dark mode and a colored header +- Upload a logo and favicon (icon shown in browser tabs) +- Add HTML for custom headers and footers +- Add [custom LESS/CSS](#css-theming) to change how elements are displayed + +## CSS Theming + +El CSS es un lenguaje de hojas de estilo que indica a los navegadores cómo mostrar los elementos de una página web. Nos permite modificar todo, desde los colores hasta las fuentes, el tamaño de los elementos y su posicionamiento, y las animaciones. Añadir CSS personalizado puede ser una gran manera de modificar su instalación de Flarum para que coincida con un tema. + +Un tutorial de CSS está más allá del alcance de esta documentación, pero hay muchos recursos en línea para aprender los fundamentos de CSS. + +:::tip + +Flarum utiliza LESS, que facilita la escritura de CSS al permitir variables, condicionales y funciones. + +::: + +## Extensiones + +El flexible [sistema de extensiones](extensions.md) de Flarum te permite añadir, eliminar o modificar prácticamente cualquier parte de Flarum. Si quieres hacer modificaciones temáticas sustanciales más allá de cambiar colores/tamaños/estilos, una extensión personalizada es definitivamente el camino a seguir. Para aprender cómo hacer una extensión, ¡consulta nuestra [documentación de extensiones](extend/README.md)! diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md new file mode 100644 index 000000000..a71a7e175 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md @@ -0,0 +1,56 @@ +# Resolución de problemas + +Si Flarum no se instala o no funciona como se espera, lo primero que debes hacer es *comprobar de nuevo* si tu entorno cumple los [requisitos del sistema](install.md#server-requirements). Si te falta algo que Flarum necesita para funcionar, tendrás que remediarlo primero. + +A continuación, deberías tomarte unos minutos para buscar en el [foro de soporte](https://discuss.flarum.org/t/support) y en el [issue tracker](https://github.com/flarum/core/issues). Es posible que alguien ya haya informado del problema y que haya una solución disponible o en camino. Si has buscado a fondo y no puedes encontrar ninguna información sobre el problema, es hora de empezar a solucionar el problema. + +## Step 0: Activate debug mode + +:::danger Skip on Production + +These debugging tools are very useful, but can expose information that shouldn't be public. These are fine if you're on a staging or development environment, but if you don't know what you're doing, skip this step when on a production environment. + +::: + +Antes de continuar, debes habilitar las herramientas de depuración de Flarum. Simplemente abre **config.php** con un editor de texto, cambia el valor de `debug` a `true`, y guarda el archivo. Esto hará que Flarum muestre mensajes de error detallados, dándote una idea de lo que está fallando. + +Si ha estado viendo páginas en blanco y el cambio anterior no ayuda, intente establecer `display_errors` a `On` en su archivo de configuración **php.ini**. + +## Paso 1: Arreglos comunes + +A lot of issues can be fixed with the following: + +* Borrar la caché del navegador +* Borrar la caché del backend con [`php flarum cache:clear`](console.md). +* Asegúrese de que su base de datos está actualizada con [`php flarum migrate`](console.md). +* Asegúrese de que la [configuración de correo electrónico](mail.md) en su panel de administración es correcta: una configuración de correo electrónico no válida causará errores al registrarse, restablecer una contraseña, cambiar correos electrónicos y enviar notificaciones. +* Comprueba que su `config.php` es correcto. Por ejemplo, asegúrate de que se utiliza la "url" correcta. +* One potential culprit could be a custom header, custom footer, or custom LESS. If your issue is in the frontend, try temporarily removing those via the Appearance page of the admin dashboard. + +También querrás echar un vistazo a la salida de [`php flarum info`](console.md) para asegurarte de que nada importante está fuera de lugar. + +## Paso 2: Reproducir el problema + +Intenta que el problema se repita. Presta mucha atención a lo que estás haciendo cuando ocurre. Does it happen every time, or only now and then? Try changing a setting that you think might affect the problem, or the order in which you're doing things. ¿Sucede en algunas condiciones, pero no en otras? + +Si has añadido o actualizado recientemente una extensión, deberías desactivarla temporalmente para ver si el problema desaparece. Asegúrate de que todas tus extensiones fueron creadas para ser usadas con la versión de Flarum que estás ejecutando. Las extensiones desactualizadas pueden causar una variedad de problemas. + +En algún momento puedes tener una idea de lo que está causando tu problema, y encontrar una manera de arreglarlo. Pero incluso si eso no sucede, probablemente se encontrará con algunas pistas valiosas que nos ayudarán a averiguar lo que está pasando, una vez que haya presentado su informe de error. + +## Paso 3: Recoger información + +Si parece que vas a necesitar ayuda para resolver el problema, es hora de ponerse a recopilar datos. Busca mensajes de error u otra información sobre el problema en los siguientes lugares: + +* En la propia página +* En la consola del navegador (Chrome: Más herramientas -> Herramientas de desarrollo -> Consola) +* Registrados en el registro de errores del servidor (p. ej. `/var/log/nginx/error.log`) +* Registrado en el registro de errores de PHP-FPM (p. ej. `/var/log/php7.x-fpm.log`) +* Registrados por Flarum (`storage/logs/flarum.log`) + +Copie cualquier mensaje en un archivo de texto y anote algunas notas sobre *cuando* se produjo el error, *qué* estaba haciendo en ese momento, etc. Asegúrate de incluir cualquier información que hayas obtenido sobre las condiciones en las que se produce el problema y en las que no. Añade toda la información posible sobre el entorno de tu servidor: Versión del sistema operativo, versión del servidor web, versión y manejador de PHP, etc. + +## Paso 4: Preparar un informe + +Una vez que hayas reunido toda la información que puedas sobre el problema, estás listo para presentar un informe de error. Por favor, sigue las instrucciones en [Reportando Bugs](bugs.md). + +Si descubres algo nuevo sobre el problema después de presentar tu informe, por favor, añade esa información al final de tu mensaje original. Es una buena idea presentar un informe incluso si has resuelto el problema por tu cuenta, ya que otros usuarios también pueden beneficiarse de tu solución. Si has encontrado una solución temporal para el problema, asegúrate de mencionarla también. \ No newline at end of file diff --git a/i18n/es/docusaurus-plugin-content-docs/version-1.x/update.md b/i18n/es/docusaurus-plugin-content-docs/version-1.x/update.md new file mode 100644 index 000000000..6d890df3c --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/version-1.x/update.md @@ -0,0 +1,110 @@ +# Actualización + +## From the Admin Dashboard + +:::info + +If you have the extension manager extension installed you can simply run the update from its interface and skip this page entirely. + +::: + +--- + +To update Flarum, you'll need to use [Composer](https://getcomposer.org). If you're not familiar with it (although you should be, because you need it to install Flarum), read [our guide](composer.md) for information on what it is and how to set it up. + +If updating across major versions (e.g. <=0.1.0 to 1.x.x, 1.x.x to 2.x.x, ...), make sure to read the appropriate "major version update guide" before running the general upgrade steps. + +## General Steps + +**Step 1:** Make sure all your extensions have versions compatible with the Flarum version you're trying to install. This is only needed across major versions (e.g. you probably don't need to check this if upgrading from v1.0.0 to v1.1.0, assuming your extensions follow recommended versioning). You can check this by looking at the extension's [Discuss thread](https://discuss.flarum.org/t/extensions), searching for it on [Packagist](http://packagist.org/), or checking databases like [Extiverse](https://extiverse.com). You'll need to remove (not just disable) any incompatible extensions before updating. Please be patient with extension developers! + +**Step 2:** Take a look at your `composer.json` file. Unless you have a reason to require specific versions of extensions or libraries, you should set the version string of everything except `flarum/core` to `*` (including `flarum/tags`, `flarum/mentions`, and other bundled extensions). Make sure `flarum/core` is NOT set to `*`. If you're targeting a specific version of Flarum, set `flarum/core` to that (e.g. `"flarum/core": "v0.1.0-beta.16`). If you just want the most recent version, use `"flarum/core": "^1.0"`. + +**Step 3:** If your local install uses [local extenders](extenders.md), make sure they are up to date with changes in Flarum. + +**Step 4:** We recommend disabling third-party extensions in the admin dashboard before updating. This isn't strictly required, but will make debugging easier if you run into issues. + +**Step 5:** Make sure your PHP version is supported by the version of Flarum you are trying to upgrade to, and that you are using Composer 2 (`composer --version)`. + +**Step 6:** Finally, to update, run: + +``` +composer update --prefer-dist --no-plugins --no-dev -a --with-all-dependencies +php flarum migrate +php flarum cache:clear +``` + +**Step 7:** If applicable, restart your PHP process and opcache. + +## Major Version Update Guides + +### Updating from Beta (<=0.1.0) to Stable v1 (^1.0.0) + +1. Do steps 1-5 above. +2. Change the version strings of all bundled extensions (`flarum/tags`, `flarum/mentions`, `flarum/likes`, etc) in `composer.json` from `^0.1.0` to `*`. +3. Change `flarum/core`'s version string in `composer.json` from `^0.1.0` to `^1.0`. +4. Remove the `"minimum-stability": "beta",` line from your `composer.json` +5. Do steps 6 and 7 above. + +## Troubleshooting Issues + +Mientras Flarum esté en fase beta, las instrucciones sobre cómo actualizar se publicarán en cada [anuncio de lanzamiento](https://discuss.flarum.org/t/blog?sort=newest). + +### Errors While Updating + +Here we'll go through several common types of issues while trying to update Flarum. + +--- + +If the output is short and contains: + +``` +Nothing to modify in lock file +``` + +Or does not list `flarum/core` as an updated package, and you are not on the latest flarum version: + +- Revisit step 2 above, make sure that all third party extensions have an asterisk for their version string. +- Make sure your `flarum/core` version requirement isn't locked to a specific minor version (e.g. `v0.1.0-beta.16` is locked, `^1.0.0` isn't). If you're trying to update across major versions of Flarum, follow the related major version update guide above. + +--- + +For other errors, try running `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO` + +If the output looks something like this: + +``` +flarum/flarum - requires flarum/core (v0.1.0-beta.15) +fof/moderator-notes 0.4.4 requires flarum/core (>=0.1.0-beta.15 <0.1.0-beta.16) +jordanjay29/flarum-ext-summaries 0.3.2 requires flarum/core (>=0.1.0-beta.14 <0.1.0-beta.16) +flarum/core v0.1.0-beta.16 requires dflydev/fig-cookies (^3.0.0) +flarum/flarum - does not require dflydev/fig-cookies (but v2.0.3 is installed) +flarum/core v0.1.0-beta.16 requires franzl/whoops-middleware (^2.0.0) +flarum/flarum - does not require franzl/whoops-middleware (but 0.4.1 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/bus (^8.0) +flarum/flarum - does not require illuminate/bus (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/cache (^8.0) +flarum/flarum - does not require illuminate/cache (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/config (^8.0) +flarum/flarum - does not require illuminate/config (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/container (^8.0) +flarum/flarum - does not require illuminate/container (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/contracts (^8.0) +flarum/flarum - does not require illuminate/contracts (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/database (^8.0) +flarum/flarum - does not require illuminate/database (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/events (^8.0) +flarum/flarum - does not require illuminate/events (but v6.20.19 is installed) +... (this'll go on for a bit) +``` + +It is very likely that some of your extensions have not yet been updated. + +- Revisit step 1 again, make sure all your extensions have versions compatible with the core version you want to upgrade to. Remove any that don't. +- Make sure you're running `composer update` with all the flags specified in the update step. + +If none of this fixes your issue, feel free to reach out on our [Support forum](https://discuss.flarum.org/t/support). Make sure to include the output of `php flarum info` and `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO`. + +### Errors After Updating + +If you are unable to access your forum after updating, follow our [troubleshooting instructions](troubleshoot.md). diff --git a/i18n/it/docusaurus-plugin-content-docs/current.json b/i18n/it/docusaurus-plugin-content-docs/current.json index b62ad0f66..466762ccc 100644 --- a/i18n/it/docusaurus-plugin-content-docs/current.json +++ b/i18n/it/docusaurus-plugin-content-docs/current.json @@ -1,6 +1,6 @@ { "version.label": { - "message": "Next", + "message": "2.x", "description": "The label for version current" }, "sidebar.guideSidebar.category.Introduction": { @@ -39,4 +39,4 @@ "message": "Internal Docs", "description": "The label for category Internal Docs in sidebar internalSidebar" } -} \ No newline at end of file +} diff --git a/i18n/it/docusaurus-plugin-content-docs/current/README.md b/i18n/it/docusaurus-plugin-content-docs/current/README.md index efd9a86cd..fee28613d 100644 --- a/i18n/it/docusaurus-plugin-content-docs/current/README.md +++ b/i18n/it/docusaurus-plugin-content-docs/current/README.md @@ -26,7 +26,7 @@ Puoi leggere di più sulla nostra [filosofia di Flarum qui](https://discuss.flar Flarum è un[software libero, open source](https://github.com/flarum/core), gestito solo da volontari. Contiamo sui contributi della comunità per aiutarci a migliorare ed espandere Flarum. -🧑 💻 Se sei uno sviluppatore, considera [di contribuire alle estensioni di Flarum o al core](contributing.md). Questo è **il** modo più efficiente per aiutare Flarum, e il vostro lavoro può avere un enorme impatto: ci sono migliaia di siti Flarum là fuori, con milioni di utenti finali totali. +🧑 💻 Se sei uno sviluppatore, considera [di contribuire alle estensioni di Flarum o al core](contributing.md). Questo è **il** modo più efficiente per aiutare Flarum, e il vostro lavoro può avere un enorme impatto: ci sono migliaia di siti Flarum là fuori, con milioni di utenti finali totali. 🧩 Se manca una funzionalità, o hai un'idea per un tema, [scrivere un'estensione personalizzata](extend/README.md) renderà Flarum molto più bello per te e per gli altri. diff --git a/i18n/it/docusaurus-plugin-content-docs/current/extend/frontend.md b/i18n/it/docusaurus-plugin-content-docs/current/extend/frontend.md index 692aa8911..9cc8aa444 100644 --- a/i18n/it/docusaurus-plugin-content-docs/current/extend/frontend.md +++ b/i18n/it/docusaurus-plugin-content-docs/current/extend/frontend.md @@ -13,9 +13,9 @@ Condividono lo stesso codice di base, quindi una volta che sai come estenderne u :::tip Typings! -Insieme al nuovo supporto TypeScript, abbiamo un pacchetto [`tsconfig`](https://www.npmjs.com/package/flarum-tsconfig) disponibile, che si dovrebbe installare come dipendenza per ottenere accesso ai nostri typings durante lo sviluppo. Assicurati di seguire le istruzioni contenute nel
README del pacchetto +Insieme al nuovo supporto TypeScript, abbiamo un pacchetto [`tsconfig`](https://www.npmjs.com/package/flarum-tsconfig) disponibile, che si dovrebbe installare come dipendenza per ottenere accesso ai nostri typings durante lo sviluppo. Assicurati di seguire le istruzioni contenute nel README del pacchetto - per configurare il supporto ai typings.

+ per configurare il supporto ai typings. ::: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/extend/notifications.md b/i18n/it/docusaurus-plugin-content-docs/current/extend/notifications.md index aeb5f1e17..b93863fbe 100644 --- a/i18n/it/docusaurus-plugin-content-docs/current/extend/notifications.md +++ b/i18n/it/docusaurus-plugin-content-docs/current/extend/notifications.md @@ -351,7 +351,7 @@ Thankfully, this is the easiest part, simply use[`NotificationSyncer`](https://g * I dati non vengono visualizzati nel database solo magicamente * * `$users`: Questo accetta un array di `user` che dovrebbe ricevere la notifica -*Che cos'è? Vuoi essere in grado di eliminare anche le notifiche? * Il modo più semplice per rimuovere una notifica è passare esattamente gli stessi dati dell'invio di una notifica, tranne che con un array vuoto di destinatari.

+*Che cos'è? Vuoi essere in grado di eliminare anche le notifiche? * Il modo più semplice per rimuovere una notifica è passare esattamente gli stessi dati dell'invio di una notifica, tranne che con un array vuoto di destinatari. Diamo un'occhiata al nostro ** ultimo ** esempio di oggi: diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/README.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/README.md new file mode 100644 index 000000000..fee28613d --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/README.md @@ -0,0 +1,45 @@ +- - - +slug: / +- - - + +# Flarum? Cos'è? + +Flarum è un potente software per creare forum di discussione nel tuo sito web. Velocissimo e facile da utilizzare con tutte le feauture necessarie per la creazione del tuo forum di successo. È anche estremamente estensibile, consentendo la massima personalizzabilità. + +![Screenshot della schermata Home di Flarum](/en/img/home_screenshot.png) + +## Obiettivi + +Flarum è la potente evoluzione di [esoTalk](https://github.com/esotalk/esoTalk) e [FluxBB](https://fluxbb.org). Progettato per essere: + +* **Veloce e semplice.** Nessun disordine e niente dipendenze complesse. Flarum è progettato in PHP per essere facile e veloce da distribuire. L'interfaccia è basata su [Mithril](https://mithril.js.org), un potente e performante framework JavaScript dall'ingombro minimo. + +* **Bello e responsive.** Il suo design si adatta a dispositivi fissi, mobili e tablet in maniera responsive. Flarum è progettato con cura per essere coerente e intuitivo su tutte le piattaforme.. + +* **Potente ed estendibile.** Personalizza, estendi e integra Flarum per creare la tua community unica. L'architettura di Flarum è molto flessibile grazie alle sue [potenti API per le estensioni](/extend/). + +* **Gratuito e aperto.** Flarum è totalmente gratuito e rilasciato sotto [Licenza MIT](https://github.com/flarum/flarum/blob/master/LICENSE). + +Puoi leggere di più sulla nostra [filosofia di Flarum qui](https://discuss.flarum.org/d/28869-flarum-philosophy-and-values). + +## Aiuta il progetto Flarum + +Flarum è un[software libero, open source](https://github.com/flarum/core), gestito solo da volontari. Contiamo sui contributi della comunità per aiutarci a migliorare ed espandere Flarum. + +🧑 💻 Se sei uno sviluppatore, considera [di contribuire alle estensioni di Flarum o al core](contributing.md). Questo è **il** modo più efficiente per aiutare Flarum, e il vostro lavoro può avere un enorme impatto: ci sono migliaia di siti Flarum là fuori, con milioni di utenti finali totali. + +🧩 Se manca una funzionalità, o hai un'idea per un tema, [scrivere un'estensione personalizzata](extend/README.md) renderà Flarum molto più bello per te e per gli altri. + +✒️ Se hai esperienza nella scrittura tecnica, i tuoi contributi alla [nostra documentazione](https://github.com/flarum/docs/issues) potrebbero aiutare i futuri utenti, gli amministratori e gli sviluppatori a sfruttare al massimo Flarum. + +🌐 Se parli più lingue, potresti [contribuire alle traduzioni](extend/language-packs.md) per rendere Flarum accessibile a innumerevoli utenti in tutto il mondo. + +💸 La Fondazione Flarum non guadagna denaro da Flarum, ma ha allo stesso tempo fatture da pagare. Le donazioni tramite [GitHub Sponsors](https://github.com/sponsors/flarum) o [OpenCollective](https://opencollective.com/flarum) sono sempre gradite e aiutano a mantenere Flarum un software di alto livello. In passato siamo stati anche in grado di supportare finanziariamente alcuni dei nostri principali sviluppatori, in modo che potessero lavorare su Flarum part-time. Questo non sarebbe possibile senza il vostro sostegno finanziario. + +🧑‍🤝‍🧑 Unisciti a [la nostra community](https://discuss.flarum.org) per parlare dello sviluppo di Flarum, ottenere aiuto con la tua estensione, o semplicemente incontrare persone fantastiche! Se hai esperienza con Flarum, puoi anche aiutare chi si affaccia allo sviluppo per la prima volta! + +🐛 Se c'è un bug che ti preoccupa, o hai un un'idea in mente per qualche nuova funzionalità, non possiamo saperlo a meno che tu non ce lo dica! Tracciamo bug, suggerimenti e futuri piani di sviluppo [tramite le "issue" di GitHub](https://github.com/flarum/core/issues). Se c'è già un problema aperto, aggiungere mi piace e ulteriori informazioni può rivelarsi molto utile! + +📣 E se Flarum ti piace, considera l'idea di parlarne sul tuo blog/twitter/Facebook! Più persone conoscono Flarum significa che più persone contribuiscono al progetto, e quindi più attività, migliori estensioni e uno sviluppo più veloce. + +Flarum non sarebbe qui senza la nostra fenomenale community. Se sei interessato a contribuire, consulta il nostro link [contributo degli sviluppatori](contributing.md) e [altri documenti](contributing-docs-translations.md) per maggiori informazioni. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/admin.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/admin.md new file mode 100644 index 000000000..9107e5f0c --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/admin.md @@ -0,0 +1,13 @@ +# Pannello di amministrazione + +Il pannello di amministrazione di Flarum un'interfaccia user-friendly per la gestione del tuo forum. Per accedere al pannello di amministrazione, clicca sul tuo **Nome** nell'angolo in alto a destra dello schermo, e scegli **Amministrazione**. È disponibile solo per gli utenti nel gruppo [gruppo](permissions.md) "Admin". + +The Admin Dashboard has the following sections, being: +- **Dashboard** - Shows the main Admin Dashboard, containing statistics and other relevant information. +- **Basics** - Shows the options to set basic forum details such as Name, Description, and Welcome Banner. +- **Email** - Allows you to configure your E-Mail settings. Refer [here](https://docs.flarum.org/mail) for more information. +- **Permissions** - Shows the permissions for each user group, and allows you to configure global and specific scopes. +- **Appearance** - Allows you to customize the forum's colors, branding and add additional CSS for customization. +- **Users** - Provides you with a paginated list of all the users in the forum, and grants you the ability to edit the user or take administrative actions. + +Apart from the above mentioned sections, the Admin Dashboard also allows you to manage your Extensions (including the flarum core extensions such as Tags) under the _Features_ section. Extensions which modify the forum theme, or allow you to use multiple languages are categorized under the _Themes_ and _Languages_ section respectively. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/bugs.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/bugs.md new file mode 100644 index 000000000..85e8ea193 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/bugs.md @@ -0,0 +1,28 @@ +# Reporting Bugs + +:::danger Security Vulnerabilities + +If you discover a security vulnerability within Flarum, please follow our [security policy](https://github.com/flarum/core/security/policy) so we can address it promptly. + +::: + +Thank you for helping us test Flarum. We're happy to have you on the team! We need people who can *troubleshoot issues patiently* and *communicate them clearly*. As you probably know, good bug reporting takes some time and effort. If you're fine with that, then let's get started! + +## Duplicates + +Found a bug already? Wonderful! We'd love to hear about it — but first you should check around to make sure you're not wasting your time on a known issue: + +- Search our [Support forum](https://discuss.flarum.org/t/support) to see if it's already been reported. +- We could be working on a fix, so search our [issue tracker](https://github.com/flarum/core/issues) too. + +If you've searched *thoroughly* and come up empty-handed, we'll welcome your report. If it's just a simple issue (a misspelled word or graphics glitch, for example) skip to the next paragraph. But if you're seeing errors, or something is clearly broken, we'll need you to gather some information first. Please head over to our [Troubleshooting](troubleshoot.md) guide and follow the instructions there. Collect as much info as you can! + +## Reporting + +We track issues on GitHub. Make sure you open your issue in the [correct repository](https://github.com/flarum), and fill out all of the information in the Bug Report template. + +If you can, check if the issue is reproducible with the latest version of Flarum. If you are using a pre-release or development version, please indicate the specific version you are using. + +Remember: the goal of a bug report is to make it easy for us to replicate the bug and fix it. You might want to read [this article](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html) for some useful tips on how to write an effective bug report. It is **required** that you clearly describe the steps necessary to reproduce the issue you are running into. Issues with no clear reproduction steps will not be triaged. If an issue labeled "needs verification" receives no further input from the issue author for more than 5 days, it will be closed. + +Once you've posted your report, we'd ask that you please *follow the discussion* and wait patiently. We may need to ask for further details or clarification; but we've always got plenty to do, and it could be a while before we can give your report the time it deserves. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md new file mode 100644 index 000000000..04147c78b --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md @@ -0,0 +1,51 @@ +# Codice di Condotta + +### _Benvenuti nella community di Flarum!_ + +... E grazie di essere con noi! Siamo entusiasti di Flarum, e siamo sempre felici di vedere persone che la pensano come noi. Vogliamo che tutti possiate ottenere il massimo da Flarum e dalla comunità Flarum, quindi vi chiediamo di leggere e seguire queste linee guida. Queste ultime si applicano sia che tu stia utilizzando il nostro forum, la chat di Discord, la comunicazione su GitHub o qualsiasi altra forma di comunicazione senza la comunità di Flarum. + +### Prima di ogni cosa, sii calmo! + +Siamo tutti qui per parlare di Flarum, e lavorare insieme per renderlo un'applicazione sempre migliore. Criticare le idee (con ragionevoli argomenti, si intende) è una parte importante per noi. Ma non lasciamo che questo faccia sfociare un post in attacchi personal, la negativit� non porta a nulla di buono. Ti chiediamo pertanto di evitare quanto segue: + +- Linguaggio scurrile o offensivo, nonché qualsiasi tipo di incitamento all'odio +- Post destinati a molestare, impersonare o diffamare altri +- Cancellazione non necessaria del contenuto pubblicato +- Tentativi di estorcere o esporre le informazioni private di altri +- Contenuti osceni o sessualmente espliciti +- Spam, messaggi di phishing e qualsiasi azione intesa a deturpare questo sito +- Discussione sulla pirateria del software e argomenti simili + +*Tutte queste azioni sono passibili di azione da parte dei moderatori. Se hai un problema con un altro membro, ti chiediamo di non affrontarlo da solo. Se è sul forum, utilizza il comando Segnala sul post in questione, quindi lascia che sia lo staff a occuparsi della situazione. Otherwise, report the violation using our [contact page](https://flarum.org/foundation/contact), option Legal. + +I nostri moderatori possono modificare o eliminare qualsiasi contenuto offensivo o di disturbo al flusso di comunicazione. Reati gravi o ripetuti possono portare alla sospensione dell'account dell'utente offensivo. Detto ciò, sii sempre gentile e calmo. 😎 + +### Fatti sentire! + +Vuoi iniziare una nuova discussione? Innanzitutto, assicurati di leggere le [nostre FAQ](faq.md) e segui i link per assicurarti di essere completamente informato sul progetto. Quindi trascorri un po' di tempo a navigare nel forum, familiarizza con [il sistema dei tag](https://discuss.flarum.org/tags), e fai qualche ricerca per parole chiave correlate al tuo argomento: ci potrebbe essere qualcuno che ha già avviato una discussione simile o identica! + +Quando sei sicuro di essere pronto per iniziare una discussione, tieni presente i seguenti punti: + +- Dagli un buon titolo! Otterrai i migliori risultati se il tuo titolo chiarisce di cosa vuoi parlare. +- Scegli i tag giusti. Ciò aumenterà  le probabilità  che il tuo post venga letto e riceva risposte più in fretta. +- Non postare ripetutamente sullo stesso argomento, perchè così facendo potresti ottenere l'effetto opposto. +- If not using a tag set aside for multilingual use, *post in English only.* We can't help you if we don't understand your posts. +- Ricorda, non è necessario firmare i tuoi post. Abbiamo il tuo profilo per farci sapere chi sei. Abbiamo il tuo profilo per farci sapere chi sei. + +Per favore, sforzati di aiutarci a mantenere le cose organizzate. Il tempo speso a riordinare è tempo che non possiamo dedicare a conoscerti, discutere i tuoi problemi e parlare di Flarum. Che dopotutto è il nostro scopo principale. + +### Le tue risposte sono importanti + +Ti stai prendendo il tempo per partecipare a una discussione, nella speranza che gli altri leggano le tue idee e le tengano in considerazione. Allora perch� non fare lo sforzo di rendere la tua risposta degna di essere letta? + +- Non rispondere al titolo. Prenditi un po di tempo per leggere tutto attentamente, ed esamina per bene tutta la conversazione. +- Chiediti se la tua risposta aggiunge davvero qualcosa alla discussione. In caso contrario, pensaci ancora prima di pubblicare. +- Evita di rispondere con una sola parola come "grazie" o "ok"; puoi usare il tasto "Mi piace" per questo. +- Evita di creare più¹ post di seguito quando uno sarebbe sufficiente. Questo è un forum, non una chat room. +- Se è probabile che la tua risposta possa deviare il corso della discussione, valuta invece di iniziare una nuova discussione. +- Se vuoi solo pubblicare un po' di sciocchezze come test, fallo nel apposita sezione di test del forum. +- Assicurati che le tue risposte forniscano feedback e supporto costruttivi per consentire una comunità  inclusiva. + +Nessuno si lamenterà  dello scherzo occasionale o dell'osservazione intelligente. Ci piace mantenere l'atmosfera leggera! Ma anche per mantenere le cose produttive, ti chiediamo di cercare di evitare di far deragliare del tutto una discussione. + +> Grazie a Dominion per il suo aiuto nella stesura delle linee guida. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/composer.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/composer.md new file mode 100644 index 000000000..5731d8e80 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/composer.md @@ -0,0 +1,152 @@ + +# Composer + +Flarum usa [Composer](https://getcomposer.org) per gestire le sue dipendenze ed estensioni. Dovrai usare composer per: + +- Install or update Flarum through the command line +- Install, update, or remove Flarum extensions through the command line + +Questa guida è una piccola base per l'utilizzo di Composer. Raccomandiamo vivamente di consultare la [documentazione ufficiale](https://getcomposer.org/doc/00-intro.md) per maggiori informazioni. + +:::info Hosting condiviso + +On shared hosting it is recommended to use the Extension Manager extension instead of Composer. It is a graphical interface for Composer that allows you to install, update and remove extensions without the need for SSH access. You can directly install Flarum using an archive file, without the need for Composer. With the extension manager pre-installed, check the [installation guide](install.md#installing-by-unpacking-an-archive) for more information. + +::: + +## Che cos’è Composer? + +> Il compositore è uno strumento per la gestione delle dipendenze in PHP. Ti permette di dichiarare le librerie su cui dipende il tuo progetto e le gestirà (installazione/aggiornamento) per te. — [Introduzione a Composer](https://getcomposer.org/doc/00-intro.md](https://getcomposer.org/doc/00-intro.md)) + +Ogni installazione di Flarum consiste principalmente nell'installazione di Flarum core e una serie di [estensioni](extensions.md). Ognuna di queste ha le sue dipendenze. + +In principio, il framework del forum gestiva le estensioni manualmente, caricando file zip contenenti il codice delle estensioni. Sembrava abbastanza semplice, ma i problemi divennero subito evidenti: + +- Il caricamento di file zip casuali da internet tende ad essere una cattiva idea. Richiedere che le estensioni vengano scaricate da una fonte come [Packagist](https://packagist.org/) rende un rende lo spam o codice malevolo difficile da scaricare, e assicura che il codice sorgente sia disponibile su GitHub per estensioni gratuite/pubbliche. +- Diciamo che l'estensione A richiede la versione v4 di alcune librerie, e l'estensione B richiede la versione v5 di quella stessa libreria. Con una soluzione basata su zip, una delle due dipendenze potrebbe prevalere sull'altra, causando una serie di problemi. Oppure entrambi tenterebbero di funzionare contemporaneamente, il che causerebbe il crash di PHP (non è possibile dichiarare la stessa classe due volte). +- I file zip possono causare molti mal di testa se si tenta di automatizzare le distribuzioni, eseguire test automatici o scalare su più nodi del server. +- There is no good way to ensure conflicting extension versions can't be installed, or that system PHP version and extension requirements are met. +- Sure, we can upgrade extensions by replacing the zip file. But what about upgrading Flarum core? And how can we ensure that extensions can declare which versions of core they're compatible with? + +Composer takes care of all these issues, and more! + +## Flarum and Composer + +When you go to [install Flarum](install.md#installing), you're actually doing 2 things: + +1. Downloading a boilerplate "skeleton" for Flarum. This includes an `index.php` file that handles web requests, a `flarum` file that provides a CLI, and a bunch of web server config and folder setup. This is taken from the [`flarum/flarum` github repository](https://github.com/flarum/flarum), and doesn't actually contain any of the code necessary for Flarum to run. +2. Installing `composer` packages necessary for Flarum, namely Flarum core, and several bundled extensions. These are called by the `index.php` and `flarum` files from step 1, and are the implementation of Flarum. These are specified in a `composer.json` file included in the skeleton. + +When you want to update Flarum or add/update/remove extensions, you'll do so by running `composer` commands. Each command is different, but all commands follow the same general process: + +1. Update the `composer.json` file to add/remove/update the package. +2. Do a bunch of math to get the latest compatible versions of everything if possible, or figure out why the requested arrangement is impossible. +3. If everything works, download new versions of everything that needs to be updated. If not, revert the `composer.json` changes + +When running `composer.json` commands, make sure to pay attention to the output. If there's an error, it'll probably tell you if it's because of extension incompatibilities, an unsupported PHP version, missing PHP extensions, or something else. + +### The `composer.json` File + +As mentioned above, the entire composer configuration for your Flarum site is contained inside the `composer.json` file. You can consult the [composer documentation](https://getcomposer.org/doc/04-schema.md) for a specific schema, but for now, let's go over an annotated `composer.json` from `flarum/flarum`: + +```json +{ + // This following section is mostly just metadata about the package. + // For forum admins, this doesn't really matter. + "name": "flarum/flarum", + "description": "Delightfully simple forum software.", + "type": "project", + "keywords": [ + "forum", + "discussion" + ], + "homepage": "https://flarum.org/", + "license": "MIT", + "authors": [ + { + "name": "Flarum", + "email": "info@flarum.org", + "homepage": "https://flarum.org/team" + } + ], + "support": { + "issues": "https://github.com/flarum/core/issues", + "source": "https://github.com/flarum/flarum", + "docs": "https://flarum.org/docs/" + }, + // End of metadata + + // This next section is the one we care about the most. + // It's a list of packages we want, and the versions for each. + // We'll discuss this shortly. + "require": { + "flarum/core": "^1.0", + "flarum/approval": "*", + "flarum/bbcode": "*", + "flarum/emoji": "*", + "flarum/lang-english": "*", + "flarum/flags": "*", + "flarum/likes": "*", + "flarum/lock": "*", + "flarum/markdown": "*", + "flarum/mentions": "*", + "flarum/nicknames": "*", + "flarum/pusher": "*", + "flarum/statistics": "*", + "flarum/sticky": "*", + "flarum/subscriptions": "*", + "flarum/suspend": "*", + "flarum/tags": "*" + }, + + // Various composer config. The ones here are sensible defaults. + // See https://getcomposer.org/doc/06-config.md for a list of options. + "config": { + "preferred-install": "dist", + "sort-packages": true + }, + + // If composer can find a stable (not dev, alpha, or beta) version + // of a package, it should use that. Generally speaking, production + // sites shouldn't run beta software unless you know what you're doing. + "prefer-stable": true +} +``` + +Let's focus on that `require` section. Each entry is the name of a composer package, and a version string. To read more about version strings, see the relevant [composer documentation](https://semver.org/). + +For Flarum projects, there's several types of entries you'll see in the `require` section of your root install's `flarum/core`: + +- You MUST have a `flarum/core` entry. This should have an explicit version string corresponding to the major release you want to install. For Flarum 1.x versions, this would be `^1.0`. +- You should have an entry for each extension you've installed. Some bundled extensions are included by default (e.g. `flarum/tags`, `flarum/suspend`, etc), [others you'll add via composer commands](extensions.md). Unless you have a reason to do otherwise (e.g. you're testing a beta version of a package), we recommend using an asterisk as the version string for extensions (`*`). This means "install the latest version compatible with my flarum/core". +- Some extensions / features might require PHP packages that aren't Flarum extensions. For example, you need the guzzle library to use the [Mailgun mail driver](mail.md). In these cases, the instructions for the extension/feature in question should explain which version string to use. + +## How to install Composer? + +As with any other software, Composer must first be [installed](https://getcomposer.org/download/) on the server where Flarum is running. There are several options depending on the type of web hosting you have. + +### Dedicated Web Server + +In this case you can install composer as recommended in the Composer [guide](https://getcomposer.org/doc/00-intro.md#system-requirements) + +### Managed / Shared hosting + +If Composer is not preinstalled (you can check this by running `composer --version`), you can use a [manual installation](https://getcomposer.org/composer-stable.phar). Just upload the composer.phar to your folder and run `/path/to/your/php7 composer.phar COMMAND` for any command documented as `composer COMMAND`. + +:::danger + +Some articles on the internet will mention that you can use tools like a PHP shell. If you are not sure what you are doing or what they are talking about - be careful! An unprotected web shell is **extremely** dangerous. + +::: + +## How do I use Composer? + +You'll need to use Composer over the **C**ommand-**l**ine **i**nterface (CLI). Be sure you can access your server over **S**ecure **Sh**ell (SSH). + +Once you have Composer installed, you should be able to run Composer commands in your SSH terminal via `composer COMMAND`. + +:::info Optimizations + +After most commands, you'll want to run `composer dump-autoload -a`. Essentially, this caches PHP files so they run faster. + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/config.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/config.md new file mode 100644 index 000000000..84ae4122a --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/config.md @@ -0,0 +1,35 @@ +# File di configurazione + +C'è solo un un eccezione in cui la configurazione di Flarum non può essere modificata tramite il pannello di amministrazione (escluso il database), ed è il file `config.php` che si trova nella radice della tua installazione di Flarum. + +Questo file, sebbene piccolo, contiene dettagli cruciali per il corretto funzionamento dell'installazione di Flarum. + +Se il file esiste, dice a Flarum che è già stato installato. Fornisce inoltre a Flarum informazioni importanti sul database e altro ancora. + +Ecco una rapida panoramica di cosa significa con un file di esempio: + +```php + false, // abilita o disabilita il debug mode, utilizzato per la risoluzione dei problemi + 'offline' => false, // abilita o disabilita la modalità di manutenzione del sito. Questo rende il tuo sito inaccessibile a tutti gli utenti (compresi gli amministratori). + 'database' => + array ( + 'driver' => 'mysql', // il driver del database, es. MySQL, MariaDB... + 'host' => 'localhost', // l'host della connessione, localhost nella maggior parte dei casi a meno di non utilizzare un servizio esterno + 'database' => 'flarum', // il nome del database nell'istanza + 'username' => 'root', // nome utente del database + 'password' => '', // password del database + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', // il prefisso delle tabelle, utile se condividi lo stesso database con altri servizi + 'port' => '3306', // la porta di connessione, di default 3306 con MySQL + 'strict' => false, + ), + 'url' => 'https://flarum.localhost', // l'URL di installazione, vorrai cambiarlo se cambi domini + 'paths' => + array ( + 'api' => 'api', // /api punta alle API + 'admin' => 'admin', // /admin punta al pannello di amministrazione + ), +); +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/console.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/console.md new file mode 100644 index 000000000..749b95974 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/console.md @@ -0,0 +1,77 @@ +# Console + +Oltre al pannello di amministrazione, Flarum fornisce diversi comandi eseguibili della console per aiutarti a gestire il tuo forum tramite il terminale. + +Using the console: + +1. `Collegarsi in ssh` nel server in cui è ospitata la tua installazione di flarum +2. `cd` to the folder that contains the file `flarum` +3. Lancia il comando `php flarum [command]` + +## Comandi di default + +### elenco + +Elenca tutti i comandi di gestione disponibili, nonché le istruzioni per l'utilizzo degli stessi + +### aiuto + +`php flarum help [command_name]` + +Mostra la guida e aiuti sul comando. + +È inoltre possibile visualizzare la guida in altri formati utilizzando il comando --format: + +`php flarum help --format=xml list` + +Per visualizzare l'elenco dei comandi disponibili, utilizzare il comando list + +### info + +`php flarum info` + +Get information about Flarum's core and installed extensions. Questo è molto utile per il debug dei problemi e dovrebbe essere condiviso quando si richiede supporto. + +### cache:clear + +`php flarum cache:clear` + +Cancella la cache del backend di Flarum, inclusi js / css generati, cache del formattatore di testo e traduzioni memorizzate. Questo comando dovrebbe essere eseguito dopo l'installazione o la rimozione di estensioni e la sua esecuzione dovrebbe essere il primo passaggio da effettuare quando si verificano problemi. + +### assets:publish + +`php flarum assets:publish` + +Publish assets from core and extensions (e.g. compiled JS/CSS, bootstrap icons, logos, etc). This is useful if your assets have become corrupted, or if you have switched [filesystem drivers](extend/filesystem.md) for the `flarum-assets` disk. + +### migrate + +`php flarum migrate` + +Esegue tutte le migrazioni in sospeso. Deve essere utilizzato quando viene aggiunta o aggiornata un'estensione che modifica il database. + +### migrate:reset + +`php flarum migrate:reset --extension [extension_id]` + +Reimposta tutte le migrazioni per un'estensione. Viene utilizzato principalmente dagli sviluppatori di estensioni, ma a volte potrebbe essere necessario eseguirlo se si rimuove un'estensione e si desidera cancellare tutti i suoi dati dal database. Tieni presente che l'estensione in questione deve essere attualmente installata (ma non necessariamente abilitata) affinché funzioni. + +### schedule:run + +`php flarum schedule:run` + +Many extensions use scheduled jobs to run tasks on a regular interval. This could include database cleanups, posting scheduled drafts, generating sitemaps, etc. If any of your extensions use scheduled jobs, you should add a [cron job](https://ostechnix.com/a-beginners-guide-to-cron-jobs/) to run this command on a regular interval: + +``` +* * * * * cd /path-to-your-flarum-install && php flarum schedule:run >> /dev/null 2>&1 +``` + +This command should generally not be run manually. + +Note that some hosts do not allow you to edit cron configuration directly. In this case, you should consult your host for more information on how to schedule cron jobs. + +### schedule:list + +`php flarum schedule:list` + +This command returns a list of scheduled commands (see `schedule:run` for more information). This is useful for confirming that commands provided by your extensions are registered properly. This **can not** check that cron jobs have been scheduled successfully, or are being run. \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md new file mode 100644 index 000000000..7b17fc28e --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md @@ -0,0 +1,26 @@ +# Docs and Translation + +## Add Documentation + +Adding documentation can help countless future Flarum users. A few ideas of what to work on: + +- User guides to help Flarum end users with some advanced Flarum features. +- More [frequently asked questions](faq.md). +- Expanded [troubleshooting](troubleshoot.md) steps. +- Step-by-step tutorials for Flarum development or installation. +- [Technical reference guides](extend/README.md) for extension developers. +- Improving literally anything else you think we should elaborate on or explain better. + +A good way to find topics to write about is to look for common questions in the [support tag](https://discuss.flarum.org/t/support) of our community. + +## Translate Flarum + +We want Flarum to be accessible to everyone, regardless of language! By contributing translations, you make it possible for many more people to enjoy Flarum. Best of all, we use user-friendly GUIs for translations, so no technical skills are necessary to help! + +Translations for Flarum core, bundled extensions, and community extensions are managed through [Weblate](https://weblate.rob006.net/projects/flarum/). + +Translations for this documentation are managed through [Crowdin](https://crowdin.com/project/flarum-docs). + +The Flarum Foundation has created the "flarum-lang" organization to support translators and ensure continuous availability of language packs. You can learn more about this by [visiting the GitHub repository](https://github.com/flarum-lang/about). + +If you want to support an existing language pack, start a new translation, or you run into issues using weblate or crowdin, it's best to [get in touch with the `flarum-lang` team](https://discuss.flarum.org/d/27519-the-flarum-language-project). diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/contributing.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/contributing.md new file mode 100644 index 000000000..1d6e6b64f --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/contributing.md @@ -0,0 +1,170 @@ +# Contribuire a Flarum + +Interessato a contribuire allo sviluppo di Flarum? È fantastico! Dalla [segnalazione di un bug](bugs.md) alla creazione di richieste particolari: ogni contributo è apprezzato e utile. Flarum non sarebbe qui senza la nostra fenomenale community. + +Prima di contribuire, leggi il [codice di condotta](code-of-conduct.md). + +Questo documento è una guida per gli sviluppatori che vogliono contribuire con codice a Flarum. Se hai appena iniziato, ti consigliamo di leggere la documentazione [Per iniziare](/extend/start.md) (per ora in inglese) sul funzionamento di Flarum. + +## Su cosa lavorare + +⚡ **Have Real Impact.** There are thousands of Flarum instances, with millions of aggregate end users. By contributing to Flarum, your code will have a positive impact on all of them. + +🔮 **Shape the Future of Flarum.** We have a long backlog, and limited time. If you're willing to champion a feature or change, it's much more likely to happen, and you'll be able to enact your vision for it. Plus, our roadmap and milestones are set by our [core development team](https://flarum.org/team), and all of us started as contributors. The best road to influence is contributing. + +🧑‍💻 **Become a Better Engineer.** Our codebase is modern, and we heavily value good engineering and clean code. There's also a lot of interesting, challenging problems to solve regarding design, infrastructure, performance, and extensibility. Especially if you're a student or early in your career, working on Flarum is a great opportunity to build development skills. + +🎠 **It's Fun!** We really enjoy working on Flarum: there's a lot of interesting challenges and fun features to build. We also have an active community on [our forums](https://discuss.flarum.org) and [Discord server](https://flarum.org/chat). + +## Setup area di sviluppo + +Dai un occhiata ai nostri prossimi [Traduardi (in inglese)](https://github.com/flarum/core/milestones) per una panoramica di ciò che deve essere fatto. Consulta le [Primi problemi](https://github.com/flarum/core/labels/Good%20first%20issue) per un elenco di problemi con cui dovrebbe essere relativamente facile iniziare. Se c'è qualcosa di cui non sei sicuro, non esitare a chiedere! Abbiamo tutti cominciato dal principio. + +Se hai intenzione di andare avanti e lavorare su qualcosa, commenta il problema pertinente o creane uno nuovo prima. In questo modo possiamo garantire che il tuo prezioso lavoro non sia vano. + +Dal momento che Flarum è così estendibile, consigliamo vivamente [i nostri documenti per le estensioni](extend/README.md) come riferimento quando si lavora sul core, così come per le estensioni in bundle. Si dovrebbe iniziare con [l'introduzione](extend/README.md) per una migliore comprensione della nostra filosofia di estensibilità. + +## Flusso di lavoro nello sviluppo + +### Impostare un codice locale + +[flarum/flarum](https://github.com/flarum/flarum) is a "skeleton" application which uses Composer to download the core package and a bunch of extensions. Source code for Flarum core, extensions, and all packages used by the aforementioned is located in the Flarum monorepo [flarum/framework](https://github.com/flarum/framework). In order to contribute to these, you'll need to fork and clone the monorepo repository locally, and then add it to your dev environment as a [Composer path repository](https://getcomposer.org/doc/05-repositories.md#path): + +```bash +git clone https://github.com/flarum/flarum.git +cd flarum + +# Or, when you want to clone directly into the current directory +git clone https://github.com/flarum/flarum.git . +# Note, the directory must be empty + +# Set up a Composer path repository for Flarum monorepo packages +composer config repositories.0 path "PATH_TO_MONOREPO/*/*" +git clone https://github.com//framework.git PATH_TO_MONOREPO +``` + +Un esempio tipico di flusso di lavoro può essere questo: + +Infine, lancia `composer install` per completare l'installazione dal percorso della repository. + +Fatto ciò la tua installazione locale è impostata, assicurati di abilitare la modalità `debug` in **config.php**, e imposta `display_errors` su `On` nella tua configurazione php. Questo ti permetterà di vedere i dettagli dell'errore sia per Flarum che per PHP. Debug mode also forces a re-compilation of Flarum's asset files on each request, removing the need to call `php flarum cache:clear` after each change to the extension's JavaScript or CSS. + +Il codice front-end di Flarum è scritto in ES6 e trasferito in JavaScript. During development you will need to recompile the JavaScript using [Node.js](https://nodejs.org/) and [`yarn`](https://yarnpkg.com/). **Please do not commit the resulting `dist` files when sending PRs**; this is automatically taken care of when changes are merged into the `main` branch. + +To contribute to the frontend, first install the JavaScript dependencies. The monorepo uses [yarn workspaces](https://classic.yarnpkg.com/lang/en/docs/workspaces/) to easily install JS dependencies across all packages within. + +```bash +cd packages/framework +yarn install +``` + +Then you can watch JavaScript files for changes during development: + +```bash +cd framework/core/js +yarn dev +``` + +The process is the same for extensions. + +```bash +cd extensions/tags/js +yarn dev +``` + +### Strumenti di sviluppo + +After you've forked and cloned the repositories you'll be working on, you'll need to set up local hosting so you can test out your changes. Flarum doesn't currently come with a development server, so you'll need to set up Apache/NGINX/Caddy/etc to serve this local Flarum installation. + +Alternatively, you can use tools like, [Laravel Valet](https://laravel.com/docs/master/valet) (Mac), [XAMPP](https://www.apachefriends.org/index.html) (Windows), or [Docker-Flarum](https://github.com/mondediefr/docker-flarum) (Linux) to serve a local forum. + +Most Flarum contributors develop with [PHPStorm](https://www.jetbrains.com/phpstorm/download/) or [Visual Studio Code](https://code.visualstudio.com/). + +## Stile del codice + +A typical contribution workflow looks like this: + +0. 🌳 **Crea un branch** per le funzionalità partendo da un branch appropriato. + * * Le correzioni di bug* dovrebbero essere inviate all'ultimo branch stabile. + * *Funzionalità minori* che sono completamente retrocompatibili con l'attuale versione di Flarum possono essere inviate all'ultimo branch stabile. + +1. 🔨 **Scrivi** un po' di codice. + * Vedi sotto per lo [stile del codice](#stile-del-codice). + * *Funzionalità minori* che sono completamente retrocompatibili con l'attuale versione di Flarum possono essere inviate all'ultimo branch stabile. + * *Major* features should always be sent to the `main` branch, which contains the upcoming Flarum release. + * Internamente usiamo lo schema di denominazione `/` (es. `tz/refactor-frontend`). + +2. 🚦 **Testa** il tuo codice. + * Aggiungi unit test in base alle esigenze durante la correzione di bug o l'aggiunta di funzionalità. + +3. 💾 **Crea dei commit** per il tuo codice con un messaggio descrittivo. + * Se la modifica risolve un problema esistente (di solito, dovrebbe) includere "Fixes #123" in una nuova riga, dove 123 è il numero dell'issue GitHub. + * Scrivi un [buon messaggio accompagnatorio](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). + * Vedi [qui](extend/testing.md) per maggiori informazioni sui test in Flarum. + +4. 🎁 **Invia** una Pull Request su GitHub. + * Riempi i campi della richiesta. + * Follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) specification. + * *Fix* commits should describe the issue fixed, not how it was fixed. + +5. 🤝 **Coinvolgi il team** di Flarum per l'approvazione. + * Riempi i campi della richiesta (pull request). + * Quando lasci un feedback, aggiungi commenti invece di sovrascriverli o eliminarli (li uniremo noi). + * NON eseguire il check-in di JavaScript nei file `dist` Verra fatto automaticamente una volta uniti. Verrà compilato tutto automaticamente durante la fusione. + +6. 🕺 **Festeggia** per aver contribuito a Flarum! + * I membri del team esamineranno il tuo codice. Potremmo suggerire alcune modifiche o miglioramenti o alternative, ma per piccoli cambiamenti la tua richiesta pull dovrebbe essere accettata rapidamente. + * Quando lasci un feedback, aggiungi commenti invece di sovrascriverli o eliminarli (li uniremo noi). + +7. 🕺 **Festeggia** per aver contribuito a Flarum. + +## Strumenti di sviluppo + +In order to keep the Flarum codebase clean and consistent, we have a number of coding style guidelines that we follow. When in doubt, read the source code. + +Don't worry if your code styling isn't perfect! StyleCI and Prettier will automatically check formatting for every pull request. This allows us to focus on the content of the contribution, not the code style. + +### PHP + +Flarum follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) coding standard and the [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) autoloading standard. On top of this, we conform to a number of [other style rules](https://github.com/flarum/framework/blob/main/.styleci.yml). We use PHP 7 type hinting and return type declarations where possible, and [PHPDoc](https://docs.phpdoc.org/) to provide inline documentation. Try and mimic the style used by the rest of the codebase in your contributions. + +* Gli spazi dei nomi dovrebbero essere in singolare (es. `Flarum\Discussion`, non `Flarum\Discussions`) +* Le interfacce dovrebbero avere il suffisso `Interface` (es. `MailableInterface`) +* Le classi astratte dovrebbero essere precedute da `Abstract` (es. `AbstractModel`) +* I tratti dovrebbero essere suffissi con `Trait` (es. `ScopeVisibilityTrait`) + +### JavaScript + +Flarum's JavaScript mostly follows the [Airbnb Style Guide](https://github.com/airbnb/javascript). We use [ESDoc](https://esdoc.org/manual/tags.html) to provide inline documentation. + +### Database + +**Columns** should be named according to their data type: +* DATETIME o TIMESTAMP: `{verbed}_at` (es. created_at, read_at) o `{verbed}_until` (eg. suspended_until) +* INT considerato come conteggio: `{noun}_count` (es. comment_count, word_count) +* Chiave esterna: `{verbed}_{entity}_id` (es. hidden_user_id) + * Il verbo può essere omesso per la relazione primaria (es. autore del post � semplicemente `user_id`) +* BOOL: `is_{adjective}` (es. is_locked) + +**Tables** should be named as follows: +* Usa la forma plurale (`discussions`) +* Separa più parole con il trattino basso (`access_tokens`) +* Per le tabelle delle relazioni, unisci i due nomi di tabella in forma singolare con un trattino basso in ordine alfabetico (es. `discussion_user`) + +### CSS + +Flarum's CSS classes roughly follow the [SUIT CSS naming conventions](https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md) using the format `.ComponentName-descendentName--modifierName`. + +### Traduzioni + +We use a [standard key format](/extend/i18n.md#appendix-a-standard-key-format) to name translation keys descriptively and consistently. + +## Contratto di licenza del collaboratore + +By contributing your code to Flarum you grant the Flarum Foundation (Stichting Flarum) a non-exclusive, irrevocable, worldwide, royalty-free, sublicensable, transferable license under all of Your relevant intellectual property rights (including copyright, patent, and any other rights), to use, copy, prepare derivative works of, distribute and publicly perform and display the Contributions on any licensing terms, including without limitation: (a) open source licenses like the MIT license; and (b) binary, proprietary, or commercial licenses. Except for the licenses granted herein, You reserve all right, title, and interest in and to the Contribution. + +You confirm that you are able to grant us these rights. You represent that You are legally entitled to grant the above license. If Your employer has rights to intellectual property that You create, You represent that You have received permission to make the Contributions on behalf of that employer, or that Your employer has waived such rights for the Contributions. + +You represent that the Contributions are Your original works of authorship, and to Your knowledge, no other person claims, or has the right to claim, any right in any invention or patent related to the Contributions. You also represent that You are not legally obligated, whether by entering into an agreement or otherwise, in any way that conflicts with the terms of this license. + +The Flarum Foundation acknowledges that, except as explicitly described in this Agreement, any Contribution which you provide is on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/current.json b/i18n/it/docusaurus-plugin-content-docs/version-1.x/current.json new file mode 100644 index 000000000..033d82500 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/current.json @@ -0,0 +1,42 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.guideSidebar.category.Introduction": { + "message": "Introduzione", + "description": "The label for category Introduction in sidebar guideSidebar" + }, + "sidebar.guideSidebar.category.Setting Up": { + "message": "Impostazioni", + "description": "The label for category Setting Up in sidebar guideSidebar" + }, + "sidebar.guideSidebar.category.Management": { + "message": "Gestione", + "description": "The label for category Management in sidebar guideSidebar" + }, + "sidebar.guideSidebar.category.Advanced": { + "message": "Advanced", + "description": "The label for category Advanced in sidebar guideSidebar" + }, + "sidebar.extendSidebar.category.Main Concepts": { + "message": "Concetti principali", + "description": "The label for category Main Concepts in sidebar extendSidebar" + }, + "sidebar.extendSidebar.category.Reference Guides": { + "message": "Guide di riferimento", + "description": "The label for category Reference Guides in sidebar extendSidebar" + }, + "sidebar.extendSidebar.category.Advanced Guides": { + "message": "Guide Avanzate", + "description": "The label for category Advanced Guides in sidebar extendSidebar" + }, + "sidebar.extendSidebar.category.Update Guides": { + "message": "Update Guides", + "description": "The label for category Update Guides in sidebar extendSidebar" + }, + "sidebar.internalSidebar.category.Internal Docs": { + "message": "Internal Docs", + "description": "The label for category Internal Docs in sidebar internalSidebar" + } +} \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/README.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/README.md new file mode 100644 index 000000000..364634ce2 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/README.md @@ -0,0 +1,40 @@ +- - - +slug: /extend +- - - + +# Estensioni di Flarum + +Flarum è minimalista, ma è anche altamente estensibile. In effetti, la maggior parte delle funzionalità fornite con Flarum sono in realtà estensioni! + +Questo approccio rende Flarum estremamente personalizzabile. Un utente può disabilitare tutte le funzionalità che non utilizza sul proprio forum e installare altre estensioni per creare un forum "cucito" su misura per la sua community. + +Per ottenere questa estensibilità, Flarum è stato costruito con ricche API e punti di estensione. Con alcune conoscenze di programmazione, puoi sfruttare queste API per aggiungere quasi tutte le funzionalità che desideri. Questa sezione della documentazione ha lo scopo di insegnarti come funziona Flarum e come utilizzare le API in modo da poter creare le tue estensioni. + +## Core vs. Estensioni + +Dove tracciamo il confine tra il nucleo di Flarum e le sue estensioni? Perché alcune funzionalità sono incluse nel core e altre no? È importante comprendere questa distinzione in modo da poter mantenere la coerenza e la qualità all'interno dell'ecosistema di Flarum. + +** Il nucleo di Flarum ** non è pensato per essere pieno di funzionalità. Piuttosto, è una base, o un framework, che fornisce un appoggio affidabile su cui costruire le estensioni. Contiene solo funzionalità di base non avanzate che sono essenziali per un forum: discussioni, post, utenti, gruppi e notifiche. + +Le ** estensioni in bundle ** sono funzionalità incluse in Flarum e abilitate per impostazione predefinita. Sono estensioni come le altre e possono essere disabilitate e disinstallate. Sebbene il loro ambito non sia inteso ad affrontare tutti i casi d'uso, l'idea è di renderli abbastanza generici e configurabili da poter soddisfare la maggioranza degli utenti finali. + +** Le estensioni di terze parti ** sono funzionalità create da altri e non sono ufficialmente supportate dal team di Flarum. Possono essere costruite e utilizzate per affrontare casi d'uso più specifici. + +Se stai cercando di risolvere un bug o un difetto del core, o di un'estensione in bundle esistente, potrebbe essere appropriato * contribuire al rispettivo progetto * piuttosto che disperdere gli sforzi su una nuova estensione di terze parti. È una buona idea iniziare una discussione sulla [Community di Flarum](https://discuss.flarum.org/) per avere opinioni anche dagli sviluppatori di Flarum. + +## Risorse utili + +- [Questa documentazione](start.md) +- [Suggerimenti per sviluppatori principianti](https://discuss.flarum.org/d/5512-extension-development-tips) +- [Sviluppatori che spiegano il loro flusso di lavoro per lo sviluppo di estensioni](https://github.com/flarum/cli) +- [Suggerimenti per il namespace delle estensioni](https://discuss.flarum.org/d/6320-extension-developers-show-us-your-workflow) +- [Documentazione js di Mithril](https://discuss.flarum.org/d/9625-flarum-extension-namespacing-tips) +- [Documenti API Laravel](https://mithril.js.org/) +- [Documenti delle API di Flarum](https://laravel.com/api/8.x/) +- [Documenti delle API di Flarum](https://api.flarum.org) +- [ES6 cheatsheet](https://github.com/DrkSephy/es6-cheatsheet) + +### Supporto + +- [Communiti ufficiale di sviluppatori di Flarum](https://discuss.flarum.org/t/dev) +- [Entra sulla nostra chat #extend su Discord](https://flarum.org/discord/) diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/admin.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/admin.md new file mode 100644 index 000000000..798b7c161 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/admin.md @@ -0,0 +1,214 @@ +# Pannello amministrazione + +La Beta 15 ha introdotto un pannello di amministrazione e un frontend per le API completamente riprogettati. Ora è più facile che mai aggiungere impostazioni o autorizzazioni alla tua estensione. + +Prima della beta 15, le impostazioni delle estensioni venivano aggiunte nel file `SettingsModal` o venivano aggiunte in una nuova pagina per impostazioni più complesse. Ora, ogni estensione ha una pagina contenente informazioni, impostazioni e autorizzazioni proprie dell'estensione. + +Puoi semplicemente registrare le impostazioni, estendere la base [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage), oppure fornire la tua pagina completamente personalizzata. + +## API Dati Estensione + +:::caution SettingsModal + +### Raccontare all'API la tua estensione + +Le impostazioni aggiunte tramite `SettingsModal` continueranno a funzionare nella beta 15, ma questo metodo **è ormai obsoleto** e verrà rimosso nelle future release. + +Semplicemente lancia la funzione `for` su `app.extensionData` passando l'ID della tua estensione. Per trovare l'ID estensione, prendi il nome del composer e sostituisci eventuali barre con trattini (esempio: 'fof/merge-discussions' diventa 'fof-merge-discussions'). Le estensioni che contengono nel nome `flarum-` e/o `flarum-ext-` verranno troncate (esempio: 'webbinaro/flarum-calendar' diventa 'webbinaro-calendar'). + +Questa nuova API ti consente di aggiungere impostazioni alla tua estensione con pochissime righe di codice. + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') +}); +``` + +Prima di poter registrare qualsiasi cosa, è necessario dire a `ExtensionData` per quale estensione si vogliono ottenere i dati. + +:::info Note + +Per il seguente esempio, useremo l'estensione fittizia 'acme/interstellar': + +::: + +### Registrazione delle impostazioni + +L'aggiunta di campi delle impostazioni in questo modo è consigliata per elementi semplici. Come regola generale, se hai solo bisogno di memorizzare le cose nella tabella delle impostazioni, questi consigli ti saranno utili. + +Per aggiungere un campo, richiama la funzione `registerSetting` dopo `for` su `app.extensionData` e passagli un 'setting object' come primo argomento. Dietro le quinte `ExtensionData` trasforma effettivamente le tue impostazioni in un file [`ItemList`](https://api.docs.flarum.org/js/master/class/src/common/utils/itemlist.ts~itemlist), puoi passare un numero di priorità come secondo argomento. + +Ecco un esempio con un elemento switch (booleano): + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerSetting( + { + setting: 'acme-interstellar.coordinates', // Questa è la chiave con cui verranno salvate le impostazioni nella tabella delle impostazioni nel database. + label: app.translator.trans('acme-interstellar.admin.coordinates_label'), // L'etichetta da mostrare che consente all'amministratore di sapere cosa fa l'impostazione. + help: app.translator.trans('acme-interstellar.admin.coordinates_help'), // Testo di aiuto opzionale dove poter commentare l'impostazione. + type: 'boolean', // Di che tipo di impostazione si tratta, le opzioni valide sono: boolean, text (o qualsiasi altro tipo di tag ) e select. + }, + 30 // Opzionale: Priorità + ) +}); +``` + +Se utilizzi `type: 'select'` l'oggetto ha un aspetto leggermente diverso: + +```js +{ + setting: 'acme-interstellar.fuel_type', + label: app.translator.trans('acme-interstellar.admin.fuel_type_label'), + type: 'select', + options: { + 'LOH': 'Liquid Fuel', // La chiave in questo oggetto è ciò che verrà memorizzato nel database, il valore è l'etichetta che l'amministratore vedrà (ricorda di usare le traduzioni se hanno senso nel tuo contesto). + 'RDX': 'Solid Fuel', + }, + default: 'LOH', +} +``` + +Inoltre, notare che ulteriori elementi nelle impostazioni saranno utilizzati come attributi del componente. Questo può essere utilizzato come testo di esempio (placeholder), restrizioni min/max, ecc: + +```js +{ + setting: 'acme-interstellar.crew_count', + label: app.translator.trans('acme-interstellar.admin.crew_count_label'), + type: 'number', + min: 1, + max: 10 +} +``` + +Se vuoi aggiungere qualcosa alle impostazioni come del testo extra o un input più complicato, puoi anche passare un callback come primo argomento che restituisce JSX. Questo callback verrà eseguito nel contesto di [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) e i valori di impostazione non verranno serializzati automaticamente. + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + . or('acme-interstellar') + .registerSetting(function () { + if (app. ession.user. sername() === 'RocketMan') { + + return ( +
+

{app. ranslator.trans('acme-interstellar. dmin.you_are_rocket_man_label')}

+ +
+ ); + } + }) +}); +``` + +### Registrazione delle autorizzazioni + +Novità nella beta 15, le autorizzazioni ora possono essere trovate in 2 posizioni. Ora puoi visualizzare le autorizzazioni individuali di ciascuna estensione sulla loro pagina. Tutte le autorizzazioni possono ancora essere trovate nella pagina delle autorizzazioni. + +Affinché ciò avvenga, i permessi devono essere registrati con `ExtensionData`. Questo viene fatto in modo simile alle impostazioni, richiama `registerPermission`. + +Argomenti: + * Permessi Oggetto + * Che tipo di autorizzazione - vedere le funzioni di [`PermissionGrid`] (https://api.docs.flarum.org/js/master/class/src/admin/components/permissiongrid.js~permissiongrid) per i tipi (rimuovi elementi dal nome) + * Priorità di `ItemList` + +Tornando alla nostra estensione "rocket" preferita: + +```js +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerPermission( + { + icon: 'fas fa-rocket', // Icone Font-Awesome + label: app.translator.trans('acme-interstellar.admin.permissions.fly_rockets_label'), // Etichetta di autorizzazione + permission: 'discussion.rocket_fly', // Nome effettivo dell'autorizzazione memorizzato nel database (e utilizzato durante il controllo dell'autorizzazione). + tagScoped: true, // Se è possibile applicare questo permesso ai Tag, non solo in maniera globale. Spiegato nel paragrafo successivo. + }, + 'start', // Il permesso di categoria verrà aggiunto alla griglia + 95 // Opzional: Priorità + ); +}); +``` + +Se la tua estensione interagisce con l'estensione [tag](https://github.com/flarum/tags) (che è abbastanza comune), si potrebbe desiderare un permesso per essere "tag scopable" (... applicato a livello del tag, non solo globalmente). Puoi farlo includendo un attributo `tagScoped`, come abbiamo visto sopra. Permessi che iniziano con la discussione `.` saranno automaticamente "tag scoped" a meno che `tagScoped: false` non sia indicato. + +Torniamo alla nostra estensione missilistica preferita: + +### Promemoria concatenamento + +Ricorda che queste funzioni possono essere tutte concatenate come: + +```js +app.extensionData + .for('acme-interstellar') + .registerSetting(...) + .registerSetting(...) + .registerPermission(...) + .registerPermission(...); +``` + +### Estensione/sovrascrittura della pagina predefinita + +A volte hai impostazioni più complicate che pasticciano con le relazioni o semplicemente desideri che la pagina abbia un aspetto completamente diverso. In questo caso, dovrai dire a `ExtensionData` che vuoi fornire la tua versione della pagina. Nota che `buildSettingComponent`, l'util utilizzato per registrare le impostazioni fornendo un oggetto descrittivo, è disponibile come metodo su `ExtensionPage` (estensione da `AdminPage`, che è una base generica per tutte le pagine di amministrazione con alcuni metodi aggiuntivi). + +Crea una nuova classe che estenda il componente `Page` o`ExtensionPage` + +```js +import ExtensionPage from 'flarum/components/ExtensionPage'; + +export default class StarPage extends ExtensionPage { + content() { + return ( +

Ciao dalla sezione impostazioni!

+ ) + } +} + +``` + +Quindi lancia `registerPage`: + +```js + +import StarPage from './components/StarPage'; + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerPage(StarPage); +}); +``` + +Questa pagina verrà visualizzata al posto di quella predefinita. + +Puoi estendere la [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) o estendere la base di `Page` e progettare la tua versione. + +## Metadati Composer.json + +Nella beta 15, le pagine di estensione lasciano spazio a informazioni aggiuntive che vengono estratte da composer.json . + +Per maggiori informationi, guarda [composer.json schema](https://getcomposer.org/doc/04-schema.md). + +| Descrizione | dovein composer.json | +| ---------------------------------------- | -------------------------------------------------------------------- | +| discuss.flarum.org link alla discussione | "forum" all'interno del tag "support" | +| Documentazione | "docs" all'interno del tag "support" | +| Supporto (email) | "email" all'interno del tag "support" | +| Sito Web | "homepage" chiave | +| Donazioni | chiave "funding" (Nota: verrà utilizzato solo il primo collegamento) | +| Sorgente | "source" all'interno del tag "support" | diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md new file mode 100644 index 000000000..869c43a38 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md @@ -0,0 +1,58 @@ +# Limitazione delle API + +Flarum viene fornito con `Flarum\Api\Middleware\ThrottleApi` [middleware](middleware.md) per limitare le richieste alle API. Questo viene eseguito su ogni percorso API e le estensioni possono aggiungere la propria logica personalizzata per limitarne le richieste. + +:::caution Percorsi del forum + +Alcuni percorsi del forum (login, registrazione, password dimenticata, etc) funzionano richiamando un API. `ThrottleApi` di middleware attualmente non viene eseguito per queste richieste, ma è in previsione per il futuro. + +::: + +## Throttlers personalizzati + +Il formato per un limitatore personalizzato è estremamente semplice: tutto ciò di cui hai bisogno è una classe di chiusura o invocabile che prenda la richiesta corrente come argomento e ne restituisca uno di: + +- `false`: Questo ignora esplicitamente la limitazione per questa richiesta, ignorando tutti gli altri limitatori +- `true`: Questo contrassegna la richiesta come da limitare. +- `null`: Significa che la limitazione non viene applicata. Qualsiasi altra uscita verrà ignorata, con lo stesso effetto di `null`. + +Le limitazioni si applicano a OGNI richiesta. Ad esempio, considera le limitazioni ai post di Flarum: + +```php +use DateTime; +use Flarum\Post\Post; + +function ($request) { + if (! in_array($request->getAttribute('routeName'), ['discussions.create', 'posts.create'])) { + return; + } + + $actor = $request->getAttribute('actor'); + + if ($actor->can('postWithoutThrottle')) { + return false; + } + + if (Post::where('user_id', $actor->id)->where('created_at', '>=', new DateTime('-10 seconds'))->exists()) { + return true; + } +}; +``` + +Le limitazioni possono essere aggiunte o rimosse tramite `ThrottleApi` in `extend.php`. Per esempio: + +```php +set('throttleAll', function () { + return false; + }) + ->remove('bypassThrottlingAttribute'), + // Other extenders +]; +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/api.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/api.md new file mode 100644 index 000000000..4121180ad --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/api.md @@ -0,0 +1,353 @@ +# API e flusso di dati + +Nel [precedente articolo](models.md)abbiamo appreso come Flarum utilizza i modelli per interagire con i dati. Qui impareremo come ottenere questi dati dal database in formato JSON-API nel frontend, e farli ritornare al backend. + +:::info + +To use the built-in REST API as part of an integration, see [Consuming the REST API](../rest-api.md). + +::: + +## Lifecycle delle richieste API + +Before we go into detail about how to extend Flarum's data API, it's worth thinking about the lifecycle of a typical API request: + +![Flarum API Flowchart](/en/img/api_flowchart.png) + +1. Una richiesta HTTP viene inviata all'API di Flarum. In genere, avviene dal frontend di Flarum, tuttavia anche programmi esterni possono interagire con l'API. L'API di Flarum segue principalmente le specifiche [JSON:API](https://jsonapi.org/), quindi di conseguenza, le richieste dovrebbero seguire [dette specifiche](https://jsonapi.org/format/#fetching). +2. La richiesta viene eseguita tramite [middleware](middleware.md), e indirizzato al controller appropriato. Puoi saperne di più sui controller nel loro insieme nella nostra [routes and content documentation](routes.md). Supponendo che la richiesta sia all'API (come nel caso di questa sezione), il controller che gestisce la richiesta sarà una sottoclasse di `Flarum\Api\AbstractSerializeController`. +3. Vengono applicate tutte le modifiche apportate dalle estensioni al controller tramite [`ApiController` extender](#extending-api-controllers). Ciò potrebbe comportare la modifica dell'ordinamento, l'aggiunta di include, la modifica del serializzatore, ecc. +4. Viene chiamato il metodo `$ this-> data ()` del controller, che fornisce alcuni dati grezzi che dovrebbero essere restituiti al client. In genere, questi dati assumeranno la forma di una raccolta o istanza di Laravel Eloquent Model, che è stato recuperato dal database. Detto questo, i dati potrebbero essere qualsiasi cosa purché il serializzatore del controller possa elaborarli. Ogni controller è responsabile dell'implementazione del proprio metodo `data`. Nota che per richieste `PATCH`, `POST`, e `DELETE`, `data` eseguirà l'operazione in questione e restituirà l'istanza del modello modificata. +5. Questi dati vengono eseguiti tramite qualsiasi callback di pre-serializzazione che le estensioni registrano tramite [`ApiController` extender](#extending-api-controllers). +6. I dati passano attraverso un [serializer](#serializers), che lo converte dal backend, nel formato compatibile con il database in JSON: formato API previsto dal frontend. Inoltre allega tutti gli oggetti correlati, che vengono eseguiti tramite i propri serializzatori. Come spiegato qui sotto, l'estensione può [aggiungere / sovrascrivere relazioni e attributi](#attributes-and-relationships) a livello della serializzazione. +7. I dati serializzati vengono restituiti come JSON al frontend. +8. Se la richiesta ha avuto origine tramite il frontend di Flarum `Store`, i dati restituiti (inclusi eventuali oggetti correlati) verranno archiviati nel file [frontend models](#frontend-models) nel frontend. + +## API Endpoints + +We learned how to use models to interact with data, but we still need to get that data from the backend to the frontend. We do this by writing API Controller [routes](routes.md), which implement logic for API endpoints. + +As per the JSON:API convention, we'll want to add separate endpoints for each operation we support. Common operations are: + +- Elencare le istanze di un modello (possibilmente anche ricerca/filtraggio) +- Ottenere una singola istanza del modello +- Creare un'istanza del modello +- Aggiornare l'istanza del modello +- Eliminazione di una singola istanza di modello + +We'll go over each type of controller shortly, but once they're written, you can add these five standard endpoints (or a subset of them) using the `Routes` extender: + +```php + (new Extend\Routes('api')) + ->get('/tags', 'tags. ndex', ListTagsController::class) + ->get('/tags/{id}', 'tags. come', ShowTagController::class) + ->post('/tags', 'tags. reate', CreateTagController::class) + ->patch('/tags/{id}', 'tags. pdate', UpdateTagController::class) + ->delete('/tags/{id}', 'tags.delete', DeleteTagController::class) +``` + +:::cautela + +Paths to API endpoints are not arbitrary! To support interactions with frontend models: + +- Il percorso può essere `/prefix/{id}` per get/update/delete, o `/prefix` per list/create. +- il prefisso (`tags` nell'esempio sopra) deve corrispondere al modello JSON:API. Utilizzerai anche questo tipo di modello nell'attributo `$type` del tuo serializer, e durante la registrazione del modello frontend (`app. tore.models.TYPE = MODEL_CLASS`). +- I metodi devono corrispondere all'esempio sopra. + +Also, remember that route names (`tags.index`, `tags.show`, etc) must be unique! + +::: + +The `Flarum\Api\Controller` namespace contains a number of abstract controller classes that you can extend to easily implement your JSON-API resources. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically create your endpoint controllers: +```bash +$ flarum-cli make backend api-controller +``` + +::: + +### Elenco risorse + +For the controller that lists your resource, extend the `Flarum\Api\Controller\AbstractListController` class. At a minimum, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a collection of models. The `data` method accepts the `Request` object and the tobscure/json-api `Document`. + +```php +use Flarum\Api\Controller\AbstractListController; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ListTagsController extends AbstractListController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + return Tag::all(); + } +} +``` + +#### Impaginazione + +You can allow the number of resources being **listed** to be customized by specifying the `limit` and `maxLimit` properties on your controller: + +```php + // Il numero di record inclusi di default. + public $limit = 20; + + // Il numero massimo di record che possono essere richiesti. + public $maxLimit = 50; +``` + +You can then extract pagination information from the request using the `extractLimit` and `extractOffset` methods: + +```php +$limit = $this->extractLimit($request); +$offset = $this->extractOffset($request); + +return Tag::skip($offset)->take($limit); +``` + +To add pagination links to the JSON:API document, use the `Document::addPaginationLinks` method. + +#### Ordinamento + +You can allow the sort order of resources being **listed** to be customized by specifying the `sort` and `sortField` properties on your controller: + +```php + // ordinamento predefinito e l'ordine da usare. + public $sort = ['name' => 'asc']; + + // I campi disponibili per essere ordinati. + public $sortFields = ['firstName', 'lastName']; +``` + +You can then extract sorting information from the request using the `extractSort` method. This will return an array of sort criteria which you can apply to your query: + +```php +use Illuminate\Support\Str; + +// ... + +$sort = $this->extractSort($request); +$query = Tag::query(); + +foreach ($sort as $field => $order) { + $query->orderBy(Str::snake($field), $order); +} + +return $query->get(); +``` + +#### Cercare e Filtrare + +Read our [searching and filtering](search.md) guide for more information! + +### Mostrare una risorsa + +For the controller that shows a single resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the list controller, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a single model. We'll learn about serializers [in just a bit](#serializers). + +```php +use Flarum\Api\Controller\AbstractShowController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ShowTagController extends AbstractShowController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + return Tag::findOrFail($id); + } +} +``` + +### Creare una risorsa + +For the controller that creates a resource, extend the `Flarum\Api\Controller\AbstractCreateController` class. This is the same as the show controller, except the response status code will automatically be set to `201 Created`. You can access the incoming JSON:API document body via `$request->getParsedBody()`: + +```php +use Flarum\Api\Controller\AbstractCreateController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class CreateTagController extends AbstractCreateController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $attributes = Arr::get($request->getParsedBody(), 'data.attributes'); + + return Tag::create([ + 'name' => Arr::get($attributes, 'name') + ]); + } +} +``` + +### Aggiornare una risorsa + +For the controller that updates a resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the create controller, you can access the incoming JSON:API document body via `$request->getParsedBody()`. + +### Cancellare una risorsa + +For the controller that deletes a resource, extend the `Flarum\Api\Controller\AbstractDeleteController` class. You only need to implement a `delete` method which enacts the deletion. The controller will automatically return an empty `204 No Content` response. + +```php +use Flarum\Api\Controller\AbstractDeleteController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; + +class DeleteTagController extends AbstractDeleteController +{ + protected function delete(Request $request) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + Tag::findOrFail($id)->delete(); + } +} +``` + +### Includere Relazioni + +To include relationships when **listing**, **showing**, or **creating** your resource, specify them in the `$include` and `$optionalInclude` properties on your controller: + +```php + // Le relazioni che sono incluse di default. + public $include = ['user']; + + // Altre relazioni disponibili per essere incluse. + public $optionalInclude = ['discussions']; +``` + +You can then get a list of included relationships using the `extractInclude` method. This can be used to eager-load the relationships on your models before they are serialized: + +```php +$relations = $this->extractInclude($request); + +return Tag::all()->load($relations); +``` + +### Estensione dei controller API + +It is possible to customize all of these options on _existing_ API controllers too via the `ApiController` extender + +```php +use Flarum\Api\Event\WillGetData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->setSerializer(MyDiscussionSerializer::class) + ->addInclude('user') + ->addOptionalInclude('posts') + ->setLimit(20) + ->setMaxLimit(50) + ->setSort(['name' => 'asc']) + ->addSortField('firstName') + ->prepareDataQuery(function ($controller) { + // Aggiungi la tua logica per personalizzare il controller + // prima che le query vengano eseguite. + }) +] +``` + +The `ApiController` extender can also be used to adjust data before serialization + +```php +use Flarum\Api\Event\WillSerializeData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->prepareDataForSerialization(function ($controller, $data, $request, $document) { + $data->load('myCustomRelation'); + }), +] +``` + +## Serializers + +Before we can send our data to the frontend, we need to convert it to JSON:API format so that it can be consumed by the frontend. You should become familiar with the [JSON:API specification](https://jsonapi.org/format/). Flarum's JSON:API layer is powered by the [tobscure/json-api](https://github.com/tobscure/json-api) library. + +A serializer is just a class that converts some data (usually [Eloquent models](models.md#backend-models)) into JSON:API. Serializers serve as intermediaries between backend and frontend models: see the [model documentation](models.md) for more information. To define a new resource type, create a new serializer class extending `Flarum\Api\Serializer\AbstractSerializer`. You must specify a resource `$type` and implement the `getDefaultAttributes` method which accepts the model instance as its only argument: + +```php +use Flarum\Api\Serializer\AbstractSerializer; +use Flarum\Api\Serializer\UserSerializer; + +class DiscussionSerializer extends AbstractSerializer +{ + protected $type = 'discussions'; + + protected function getDefaultAttributes($discussion) + { + return [ + 'title' => $discussion->title, + ]; + } +} +``` + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically create your serializer: +```bash +$ flarum-cli make backend api-serializer +``` + +::: + +### Attributi e relazioni + +You can also specify relationships for your resource. Simply create a new method with the same name as the relation on your model, and return a call to `hasOne` or `hasMany` depending on the nature of the relationship. You must pass in the model instance and the name of the serializer to use for the related resources. + +```php + protected function user($discussion) + { + return $this->hasOne($discussion, UserSerializer::class); + } +``` + +### Estendere i Serializers + +To add **attributes** and **relationships** to an existing resource type, use the `ApiSerializer` extender: + +```php +use Flarum\Api\Serializer\UserSerializer; + +return [ + (new Extend\ApiSerializer(UserSerializer::class)) + // One attribute at a time + ->attribute('firstName', function ($serializer, $user, $attributes) { + return $user->first_name + }) + // Multiple modifications at once, more complex logic + ->mutate(function($serializer, $user, $attributes) { + $attributes['someAttribute'] = $user->someAttribute; + if ($serializer->getActor()->can('administrate')) { + $attributes['someDate'] = $serializer->formatDate($user->some_date); + } + + return $attributes; + }) + // API relationships + ->hasOne('phone', PhoneSerializer::class) + ->hasMany('comments', CommentSerializer::class), +] +``` + +### Serializzatori Non-Model e `ForumSerializer` + +Serializers don't have to correspond to Eloquent models: you can define JSON:API resources for anything. For instance, Flarum core uses the [`Flarum\Api\Serializer\ForumSerializer`](https://api.docs.flarum.org/php/master/flarum/api/serializer/forumserializer) to send an initial payload to the frontend. This can include settings, whether the current user can perform certain actions, and other data. Many extensions add data to the payload by extending the attributes of `ForumSerializer`. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/assets.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/assets.md new file mode 100644 index 000000000..f2dfd46eb --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/assets.md @@ -0,0 +1,7 @@ +# Risorse Estensione + +Alcune estensioni potrebbero voler includere asset come immagini o file JSON nel loro codice sorgente (non si tratta di upload, che richiederebbe probabilmente un apposito [filesystem](filesystem.md)). + +Lavorare con gli asset è in realtà molto semplice. Basta creare una cartella `assets` nella radice principale della tua estensione, e posizionare tutti i file al suo interno. Flarum copierà automaticamente tali file nella propria directory `assets` (o altra posizione di archiviazione se [impostata da un estensione](filesystem.md)) ogni volta che l'estensione è abilitata o [`php flarum assets:publish`](../console.md) viene eseguito. + +Se si utilizza il driver di archiviazione predefinito, le risorse saranno disponibili all'url `https://FORUM_URL/assets/extensions/EXTENSION_ID/file.path`. Tuttavia, poiché altre estensioni potrebbero usare filesystem remoti, si consiglia di serializzare l'url alle risorse di cui hai bisogno nel backend. See [Flarum's serialization of the logo and favicon URLs](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Serializer/ForumSerializer.php#L85-L86) for an example. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md new file mode 100644 index 000000000..fcfdfce7f --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md @@ -0,0 +1,206 @@ +# Autorizzazione + +Come con qualsiasi framework, Flarum consente di limitare determinate azioni e contenuti a determinati utenti. Esistono 2 sistemi paralleli per questo: + +- Il processo di autorizzazione determina se un utente può eseguire una determinata azione. +- La visibilità può essere applicata a una query di database per limitare in modo efficiente i record a cui gli utenti possono accedere. Questo è documentato nel nostro articolo [modelli di visibilità](model-visibility.md). + +## Processo di autorizzazione + +Il processo di autorizzazione viene utilizzato per verificare se una persona è autorizzata a eseguire determinate azioni. Ad esempio, vogliamo verificare se un utente è autorizzato prima di: + +- Poter accedere al pannello di amministrazione +- Iniziare una discussione +- Modificare un post +- Aggiornare il profilo di un altro utente + +Ciascuno di questi è determinato da criteri univoci: in alcuni casi è sufficiente un flag; altrimenti, potremmo aver bisogno di una logica personalizzata. + +## Visibility Scoping + +Le richieste di autorizzazione vengono effettuate con 3 parametri, con logica contenuta in [`Flarum\User\Gate`](https://api.docs.flarum.org/php/master/flarum/user/gate): + +1. L'attore: l'utente che tenta di eseguire l'azione +2. L'abilità: una stringa che rappresenta l'azione che l'attore sta tentando +3. Gli argomenti: di solito un'istanza di un modello di database che è l'oggetto dell'azione, ma potrebbe essere qualsiasi cosa. + +Per prima cosa, eseguiamo l'intera richiesta (tutti e tre i parametri) attraverso tutte le [policies](#policies) registrate dalle estensioni e dal core. Le policy sono blocchi di logica forniti dal core e dalle estensioni che determinano se l'attore può eseguire l'azione sugli argomenti. I criteri possono restituire uno dei seguenti valori: + +- `Flarum\User\Access\AbstractPolicy::ALLOW` (tramite `$this->allow()`) +- `Flarum\User\Access\AbstractPolicy::DENY` (tramite `$this->deny()`) +- `Flarum\User\Access\AbstractPolicy::FORCE_ALLOW` (tramite `$this->forceAllow()`) +- `Flarum\User\Access\AbstractPolicy::FORCE_DENY` (tramite `$this->forceDeny()`) + +I risultati delle policy sono considerati prioritari `FORCE_DENY` > `FORCE_ALLOW` > `DENY` > `ALLOW`. Ad esempio, se viene restituita una singola policy `FORCE_DENY`, tutte le altre policy verranno ignorate. Se una policy restituisce `DENY` e altre 10 restituiscono `ALLOW`, la richiesta verrà rifiutata. Ciò consente di prendere decisioni indipendentemente dall'ordine in cui le estensioni vengono avviate. Le policy sono estremamente potenti: se l'accesso viene negato in fase di policy, questo sovrascriverà i permessi dei gruppi e i privilegi di amministratore. + +In secondo luogo, se tutte le policy restituiscono null (o non restituiscono nulla), controlliamo se l'utente è in un gruppo che ha un permesso che consenta l'azione (nota che sia i permessi che le azioni sono rappresentati sotto forma di stringhe). In tal caso, autorizziamo l'azione. Guarda la [Documentazione su gruppi e permessi](permissions.md) per maggiori informazioni. + +Quindi, se l'utente è nel gruppo admin, autorizzeremo l'azione. + +Infine, poiché abbiamo esaurito tutti i controlli, daremo per scontato che l'utente non sia autorizzato e negheremo la richiesta. + +## Autorizzazioni del frontend + +Il sistema di autorizzazione di Flarum è accessibile attraverso metodi pubblici delle classi `Flarum\User\User`. I più importanti sono elencati di seguito; altri sono documentati nelle [documentazioni PHP API](https://api.docs.flarum.org/php/master/flarum/user/user). + + +In questo esempio, useremo `$actor` come istanza di `Flarum\User\User`, `'viewForum'` e `'reply'` come esempi di abilità, e `$discussion` (istanza di `Flarum\Discussion\Discussion`) come esempio di argomento. + +```php +// Verifica se un utente può eseguire un'azione. +// ATTENZIONE: questo dovrebbe essere usato con cautela, poiché in realtà +// non viene eseguito attraverso il processo di autorizzazione, quindi non tiene conto delle policy. +$canDoSomething = $actor->can('viewForum'); + +// Verifica se un utente può eseguire un'azione su un argomento. +// Tuttavia, è utile nell'implementazione di criteri personalizzati. +$canDoSomething = $actor->can('reply', $discussion); + +// Genera un'eccezione PermissionDeniedException se un utente non può eseguire un'azione. +$actpr->assertAdmin(); + +// Controlla se uno dei gruppi dell'utente dispone di un'autorizzazione. +$actor->assertCan('viewForum'); +$actor->assertCan('reply', $discussion); + +// Genera un'eccezione NotAuthenticatedException se l'utente non ha efettuato il login. +$actor->assertRegistered(); + +// Genera un'eccezione PermissionDeniedException se l'utente non è un amministratore. +$actorHasPermission = $actor->hasPermission(`viewForum`); +``` + +## Policy personalizzate + +I criteri ci consentono di utilizzare una logica personalizzata oltre a semplici gruppi e autorizzazioni quando si valuta l'autorizzazione per un'abilità con un soggetto. Per esempio: + +- Vogliamo consentire agli utenti di modificare i post anche se non sono moderatori, ma solo i propri post. +- A seconda delle impostazioni, potremmo consentire agli utenti di rinominare le proprie discussioni a tempo indeterminato, per un breve periodo di tempo dopo la pubblicazione o per niente. + +Come descritto [qui](#how-it-works), ad ogni controllo di autorizzazione, interroghiamo tutte le politiche registrate per il modello del target o qualsiasi classe genitore del modello del target. Se non viene fornito alcun target, verranno applicati i criteri egistrati come "global". + +Quindi, come viene "verificato" un criterio? + +Innanzitutto, controlliamo se la classe del criterio ha un metodo con lo stesso nome dell'abilità che viene valutata. In tal caso, lo eseguiamo con l'attore e il soggetto come parametri. Se quel metodo restituisce un valore non nullo, restituiamo quel risultato. In caso contrario, si passa alla fase successiva (non necessariamente al criterio successivo). + +Quindi, controlliamo se la classe policy ha un metodo chiamato `can`. In tal caso, lo eseguiamo con l'attore, l'abilità e il soggetto e restituiamo il risultato. + +Se "can" non esiste o restituisce null, abbiamo finito con questo criterio e procediamo a quello successivo. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +È possibile utilizzare la CLI per generare automaticamente i criteri: +```bash +$ flarum-cli make backend policy +``` + +::: + +### Come funziona + +Diamo un'occhiata ad alcuni esempi tratti da [Flarum Tags](https://github.com/flarum/tags/blob/master/src/Access/TagPolicy). + +```php +is_restricted) { + return $actor->hasPermission('tag'.$tag->id.'.startDiscussion') ? $this->allow() : $this->deny(); + } + } + + /** + * @param User $actor + * @param Tag $tag + * @return bool|null + */ + public function addToDiscussion(User $actor, Tag $tag) + { + return $this->startDiscussion($actor, $tag); + } +} +``` + +Possiamo anche avere criteri globali, che vengono eseguiti quando `$ user-> can ()` viene chiamato senza un'istanza del modello di destinazione. Di nuovo dai tag: + +```php +settings = $settings; + } + + /** + * @param Flarum\User\User $actor + * @param string $ability + * @return bool|void + */ + public function can(User $actor, string $ability) + { + if (in_array($ability, ['viewForum', 'startDiscussion'])) { + $enoughPrimary = count(Tag::getIdsWhereCan($actor, $ability, true, false)) >= $this->settings->get('min_primary_tags'); + $enoughSecondary = count(Tag::getIdsWhereCan($actor, $ability, false, true)) >= $this->settings->get('min_secondary_tags'); + + if ($enoughPrimary && $enoughSecondary) { + return $this->allow(); + } else { + return $this->deny(); + } + } + } +} +``` + +### Come utilizzare le autorizzazioni + +ed uno globale per il modelle `Discussion`: + +```php +use Flarum\Extend; +use Flarum\Tags\Tag; +use YourNamespace\Access; + +return [ + // Other extenders + (new Extend\Policy()) + ->modelPolicy(Tag::class, Access\TagPolicy::class) + ->globalPolicy(Access\GlobalPolicy::class), + // Other extenders +]; +``` + +## Autorizzazioni del frontend + +Di solito, vorrai utilizzare i risultati dell'autorizzazione nella logica del frontend. Ad esempio, se un utente non dispone dell'autorizzazione per visualizzare gli utenti di ricerca, non dovremmo inviare richieste a quell'endpoint. E se un utente non ha il permesso di modificare gli utenti, non dovremmo mostrare le voci di menu che consentono di effettuare tali modifiche. + +Poiché non possiamo eseguire controlli di autorizzazione nel frontend, dobbiamo eseguirli nel backend e allegarli alla serializzazione dei dati che stiamo inviando. Permessi globali come (`viewForum`, `viewUserList`) possono essere inclusi in `ForumSerializer`, ma per l'autorizzazione specifica dell'oggetto, potremmo voler includere quelli con altri parametri. Ad esempio, quando restituiamo l'elenco delle discussioni, controlliamo se l'utente può rispondere, rinominare, modificare ed eliminarle oggetti, e memorizzare quei dati nel modello di discussione frontend. È quindi accessibile tramite `discussion.canReply()` o `discussion.canEdit()`, ma non c'è niente di magico qui: è solo un altro attributo inviato dal serializzatore. + +Esistono in realtà due tipi di scoper: diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md new file mode 100644 index 000000000..8d7a4eda1 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md @@ -0,0 +1,215 @@ +# Eventi backend + +Spesso, un'estensione vorrà reagire ad alcuni eventi che si verificano da qualche parte in Flarum. Ad esempio, potremmo voler incrementare un contatore quando viene pubblicata una nuova discussione, inviare un'e-mail di benvenuto quando un utente accede per la prima volta o aggiungere tag a una discussione prima di salvarla nel database. Questi eventi sono noti come ** domain events ** e vengono trasmessi attraverso il framework [Laravel's event system](https://laravel.com/docs/6.x/events). + +Per un elenco completo degli eventi di backend, vedere la nostra [API documentation](https://api.docs.flarum.org/php/master/search.html?search=Event). Le classi di eventi di dominio sono generalmente organizzate così `Flarum\TYPE\Event`. + + +:::info [Flarum CLI](https://github.com/flarum/cli) + +È possibile utilizzare la CLI per generare automaticamente gli Event Listener: +```bash +use Flarum\Extend; +use Flarum\Post\Event\Deleted; +use Symfony\Contracts\Translation\TranslatorInterface; + + +return [ + (new Extend\Event) + ->listen(Deleted::class, function($event) { + // do something here + }) + ->listen(Deleted::class, PostDeletedListener::class) +]; + + +class PostDeletedListener +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function handle(Deleted $event) + { + // Your logic here + } +} +``` + +::: + +## Ascolto di eventi + +Puoi allegare un ascoltatore a un evento utilizzando il file [`Event`](https://api.docs.flarum.org/php/master/flarum/extend/event) [extender](start.md#extenders): + +```php +use Flarum\Post\Event\Deleted; +use Illuminate\Contracts\Events\Dispatcher; + + +class SomeClass +{ + /** + * @var Dispatcher + */ + protected $events; + + /** + * @param Dispatcher $events + */ + public function __construct(Dispatcher $events) + { + $this->events = $events; + } + + public function someMethod() + { + // Logic + $this->events->dispatch( + new Deleted($somePost, $someActor) + ); + // More Logic + } +} +``` +```php +class PostDeletedListener +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function handle(Deleted $event) + { + // Your logic here + } +} +``` + +Come mostrato sopra, è possibile utilizzare una classe listener invece di un callback. Questo ti permette di [iniettare dipendenze](https://laravel.com/docs/6.x/container) alcune classi. In questo esempio risolviamo un'istanza di un traduttore, ma possiamo iniettare tutto ciò che vogliamo/di cui abbiamo bisogno. + +È inoltre possibile ascoltare più eventi in una sola volta tramite un event subscriber. Questo è utile per raggruppare le funzionalità comuni; per esempio, se si desidera aggiornare alcuni metadati sulle modifiche ai post: + +```php +use Flarum\Extend; +use Flarum\Post\Event\Deleted; +use Flarum\Post\Event\Saving; +use Symfony\Contracts\Translation\TranslatorInterface; + + +return [ + (new Extend\Event) + ->subscribe(PostEventSubscriber::class), +]; +``` +```php +class PostEventSubscriber +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function subscribe($events) + { + $events->listen(Deleted::class, [$this, 'handleDeleted']); + $events->listen(Saving::class, [$this, 'handleSaving']); + } + + public function handleDeleted(Deleted $event) + { + // Your logic here + } + + public function handleSaving(Saving $event) + { + // Your logic here + } +} +``` + +## Invio di eventi + +L'invio di eventi è molto semplice. Tutto quello che devi fare è iniettare `Illuminate\Contracts\Events\Dispatcher` nella tua classe, e chiamare poi il metodo `dispatch`. Per esempio: + +```php +use Flarum\Post\Event\Deleted; +use Illuminate\Contracts\Events\Dispatcher; + + +class SomeClass +{ + /** + * @var Dispatcher + */ + protected $events; + + /** + * @param Dispatcher $events + */ + public function __construct(Dispatcher $events) + { + $this->events = $events; + } + + public function someMethod() + { + // Logic + $this->events->dispatch( + new Deleted($somePost, $someActor) + ); + // More Logic + } +} +``` + +## Eventi personalizzati + +In qualità di sviluppatore di estensioni, puoi definire i tuoi eventi per consentire a te stesso (o ad altre estensioni) di reagire agli eventi nella tua estensione. Gli eventi sono generalmente istanze di classi semplici (non è necessario estendere nulla). Quando si definisce un nuovo evento, in genere si desidera utilizzare proprietà pubbliche e forse alcuni metodi per la comodità degli utenti. Ad esempio, se diamo un'occhiata a `Flarum\Post\Event\Deleted`, è solo un contenitore di alcuni dati: + +```php +post = $post; + $this->actor = $actor; + } +} +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/cli.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/cli.md new file mode 100644 index 000000000..5e9d65f17 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/cli.md @@ -0,0 +1,15 @@ +# Sviluppatori che spiegano il loro flusso di lavoro per lo sviluppo di estensioni + +The Flarum development ecosystem is oriented around many small, modules, interacting extensions. This is a very powerful and flexible paradigm, but it also brings the maintenance cost of creating and maintaining all these extensions. + +We've created the Flarum CLI (command line interface) as a tool to help developers by automating some repetitive and menial tasks, and allow them to get into the actual work without much hassle. + +Major updates about Flarum CLI will be published [on this discussion](https://discuss.flarum.org/d/28427-flarum-cli-v10). + +See the [package's readme](https://github.com/flarum/cli#readme) for information on: + +- Installazione +- Usage +- Upgrading +- Available commands +- Some implementation details, if you're interested diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/console.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/console.md new file mode 100644 index 000000000..6d2d24689 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/console.md @@ -0,0 +1,70 @@ +# Console + +Flarum consente agli sviluppatori di estensioni di aggiungere comandi personalizzati nella console oltre a [quelli di default](../console.md) insiti nel core di Flarum. + +Tutto lo sviluppo dei comandi della console viene eseguito nel back-end utilizzando PHP. Per creare un comando della console personalizzato, dovrai creare una classe che estende `\Flarum\Console\AbstractCommand`. + +```php +use Flarum\Console\AbstractCommand; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; + +class YourCommand implements AbstractCommand { + protected function configure() + { + $this + ->setName('IL TUO COMANDO QUI') + ->setDescription('LA DESCRIZIONE DLE TUO COMANDO'); + } + protected function fire() + { + // La tua logica qui! + } +} +``` + +:::info [Flarum CLI](https://github.com/flarum/cli) + +:::tip Comandi pianificati +```bash +$ flarum-cli make backend command +``` + +::: + +## Registrazione dei comandi della Console + +Per registrare i comandi della console, usa l'estensore `Flarum\Extend\Console` nel file `extend.php` della tua estensione: + +```php +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; + +return [ + // Other extenders + (new Extend\Console())->command(CustomCommand::class) + // Other extenders +]; +``` + +## Scheduled Commands + +La [fof/console library](https://github.com/FriendsOfFlarum/console) consente di programmare l'esecuzione dei comandi a intervalli regolari! + + +```php +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; +use Illuminate\Console\Scheduling\Event; + +return [ + // Other extenders + (new Extend\Console())->schedule('cache:clear', function (Event $event) { + $event->everyMinute(); + }, ['Arg1', '--option1', '--option2']), + // Other extenders +]; +``` + +Nella callback fornita come secondo argomento, puoi chiamare metodi sull'oggetto [$event](https://laravel.com/api/8.x/Illuminate/Console/Scheduling/Event.html) per pianificare operazioni ricorrenti (o applicare altre opzioni). Vedi la documentazione [Laravel](https://laravel.com/docs/8.x/scheduling#scheduling-artisan-commands) per maggiori informazioni. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/data.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/data.md new file mode 100644 index 000000000..faa5d5e86 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/data.md @@ -0,0 +1,568 @@ +# Lavorare con i dati + +I dati sono la base di qualsiasi forum, quindi dovrai giocarci bene se vuoi che la tua estensione faccia qualcosa di utile. Questo documento illustra il modo in cui i dati fluiscono in Flarum, dal database all'API JSON al frontend, e di nuovo indietro. + +Flarum fa uso di [componenti Database Laravel](https://laravel.com/docs/database). È necessario familiarizzare con questi componenti prima di procedere, poiché si presume che la conoscenza di questi sia assodata. + + +## Ciclo di vita delle richieste API + +Prima di entrare nei dettagli su come estendere l'API di dati di Flarum, vale la pena pensare al ciclo di vita di una tipica richiesta di dati: + +1. Una richiesta HTTP viene inviata all'API di Flarum. In genere, avviene dal frontend di Flarum, tuttavia anche programmi esterni possono interagire con l'API. L'API di Flarum segue principalmente le specifiche [JSON:API](https://jsonapi.org/), quindi di conseguenza, le richieste dovrebbero seguire [dette specifiche](https://jsonapi.org/format/#fetching). +2. La richiesta viene eseguita tramite [middleware](middleware.md), e indirizzato al controller appropriato. Puoi saperne di più sui controller nel loro insieme nella nostra [routes and content documentation](routes.md). Supponendo che la richiesta sia all'API (come nel caso di questa sezione), il controller che gestisce la richiesta sarà una sottoclasse di `Flarum\Api\AbstractSerializeController`. +3. Vengono applicate tutte le modifiche apportate dalle estensioni al controller tramite [`ApiController` extender](#extending-api-controllers). Ciò potrebbe comportare la modifica dell'ordinamento, l'aggiunta di include, la modifica del serializzatore, ecc. +4. Viene chiamato il metodo `$ this-> data ()` del controller, che fornisce alcuni dati grezzi che dovrebbero essere restituiti al client. In genere, questi dati assumeranno la forma di una raccolta o istanza di Laravel Eloquent Model, che è stato recuperato dal database. Detto questo, i dati potrebbero essere qualsiasi cosa purché il serializzatore del controller possa elaborarli. Ogni controller è responsabile dell'implementazione del proprio metodo `data`. Nota che per richieste `PATCH`, `POST`, e `DELETE`, `data` eseguirà l'operazione in questione e restituirà l'istanza del modello modificata. +5. Questi dati vengono eseguiti tramite qualsiasi callback di pre-serializzazione che le estensioni registrano tramite [`ApiController` extender](#extending-api-controllers). +6. I dati passano attraverso un [serializer](#serializers), che lo converte dal backend, nel formato compatibile con il database in JSON: formato API previsto dal frontend. Inoltre allega tutti gli oggetti correlati, che vengono eseguiti tramite i propri serializzatori. Come spiegato qui sotto, l'estensione può [aggiungere / sovrascrivere relazioni e attributi](#attributes-and-relationships) a livello della serializzazione. +7. I dati serializzati vengono restituiti come JSON al frontend. +8. Se la richiesta ha avuto origine tramite il frontend di Flarum `Store`, i dati restituiti (inclusi eventuali oggetti correlati) verranno archiviati nel file [frontend models](#frontend-models) nel frontend. + +## Migrazioni + +Se vogliamo utilizzare un modello personalizzato o aggiungere attributi a uno esistente, sarà necessario modificare il database per aggiungere tabelle / colonne. Di solito viene fatto tramite le migrazioni. + +Le migrazioni sono come il controllo della versione per il tuo database, permettendoti di modificare facilmente lo schema del database di Flarum in modo sicuro. Le migrazioni di Flarum sono molto simili a [Laravel's](https://laravel.com/docs/migrations), anche se ci sono alcune differenze. + +Le migrazioni risiedono all'interno di una cartella opportunamente denominata `migrations` nella directory delle estensioni. Le migrazioni dovrebbero essere denominate nel formato `YYYY_MM_DD_HHMMSS_snake_case_description` in modo che siano elencati ed eseguiti in ordine di creazione. + +### Struttura della migrazioni + +In Flarum, i file di migrazione dovrebbero ** restituire un array ** con due funzioni: `up` e `down`. La funzione `up` viene utilizzato per aggiungere nuove tabelle, colonne o indici al database, mentre la funziona `down` dovrebbe invertire queste operazioni. Queste funzioni ricevono un'istanza di [Laravel schema builder](https://laravel.com/docs/6.x/migrations#creating-tables) che puoi usare per modificare lo schema del database: + +```php + function (Builder $schema) { + // up migration + }, + 'down' => function (Builder $schema) { + // down migration + } +]; +``` + +Per attività comuni come la creazione di una tabella o l'aggiunta di colonne a una tabella esistente, Flarum fornisce alcuni helper che costruiscono questo array per te, e si occupano di scrivere la logica di migrazione `down` al tuo posto. Questi sono disponibili come metodi statici nelle classi `Flarum\Database\Migration`. + +### Ciclo di vita delle migrazioni + +Le migrazioni vengono applicate quando l'estensione viene abilitata per la prima volta o quando è abilitata e ci sono alcune migrazioni in sospeso. Le migrazioni eseguite vengono registrate nel database, e se ne vengono trovate alcune nella cartella migrazioni di un estensione, non ancora espletate, vengono eseguite. + +Le migrazioni possono anche essere applicate manualmente con il comando `php flarum migrate` necessario anche per aggiornare le migrazioni di un'estensione già abilitata. Per annullare le modifiche applicate dalle migrazioni, è necessario fare clic su "Disinstalla" accanto a un'estensione nel pannello di amministrazione, o utilizzare in alternativa il comando `php flarum migrate:reset`. Non può rompersi nulla eseguento il comando `php flarum migrate` anche se è stato appena eseguito - le migrazioni infatti non verranno reiterate. + +Al momento non sono presenti hook a livello del composer per la gestione delle migrazioni (es. aggiornare un estensione con `composer update` non eseguirà le sue migrazioni in sospeso). + +### Creazione di tabelle + +Per creare una tabella, utilizza l'helper `Migration::createTable`. `createTable` accetta due argomenti. Il primo è il nome della tabella, mentre il secondo è `Closure` che riceve un oggetto `Blueprint` che può essere utilizzato per definire la nuova tabella: + +```php +use Flarum\Database\Migration; +use Illuminate\Database\Schema\Blueprint; + +return Migration::createTable('users', function (Blueprint $table) { + $table->increments('id'); +}); +``` + +Quando si crea la tabella, è possibile utilizzare uno qualsiasi dei generatori di schemi [column methods](https://laravel.com/docs/6.x/migrations#creating-columns) +per definire le colonne della tabella. + +### Rinominare tabelle + +Per rinominare una tabella di database esistente, utilizzare il comando `Migration::renameTable`: + +```php +return Migration::renameTable($from, $to); +``` + +### Creazione / eliminazione di colonne + +Per aggiungere colonne ad una tabella esistente, utilizza l'helper `Migration::addColumns`.`addColumns` accetta due argomenti. Il primo è il nome della tabella. Il secondo è un array di definizioni di colonne, con la chiave che è il nome della colonna. Il valore di ogni elemento è un array con le definizioni della colonna, come inteso dal metodo Laravel `Illuminate\Database\Schema\Blueprint::addColumn()`. Il primo valore è il tipo di colonna a cui vengono passati tutti gli altri valori con `addColumn`. + +```php +return Migration::addColumns('users', [ + 'email' => ['string', 'nullable' => true], + 'discussion_count' => ['integer', 'unsigned' => true] +]); +``` + +Per eliminare colonne da una tabella esistente, utilizzare il domando `Migration::dropColumns`, che utilizza gli stessi argomenti di `addColumns`. Proprio come quando si rilasciano le tabelle, è necessario specificare le definizioni complete delle colonne in modo che la migrazione possa essere annullata in modo pulito. + +### Rinominare colonne + +Per rinominare le colonne utilizza il comando `Migration::renameColumns`.`renameColumns` accetta due argomenti. Il primo è il nome della tabella, mentre il secondo è un array di nomi di colonne da rinominare: + +```php +return Migration::renameColumns('users', ['from' => 'to']); +``` + +### Migrazioni dei dati (avanzatato) + +Una migrazione non deve modificare la struttura del database: è possibile utilizzare una migrazione per inserire, aggiornare o eliminare righe in una tabella. Ad esempio, potresti utilizzare le migrazioni per assegnare [permessi personalizzati](permissions.md) a gruppi diversi da Admin, o fornire alcuni dati iniziali per un modello Eloquent personalizzato. Dato che hai accesso a [Eloquent Schema Builder](https://laravel.com/docs/6.x/migrations#creating-tables), tutto è possibile (anche se, ovviamente, dovresti essere estremamente cauto e testare ampiamente la tua estensione). + +Le migrazioni dei dati sono il modo consigliato per specificare le impostazioni e le autorizzazioni predefinite. + +## Modelli di backend + +Con tutte le tue nuove eleganti tabelle e colonne di database, vorrai un modo per accedere ai dati sia nel backend che nel frontend. Sul back-end è piuttosto semplice: devi solo avere familiarità con [Eloquent](https://laravel.com/docs/6.x/eloquent). + +### Aggiunta di nuovi modelli + +Se hai aggiunto una nuova tabella, dovrai impostare un nuovo modello per essa. Piuttosto che estendere la classe `Model` direttamente, dovrai estendere `Flarum\Database\AbstractModel` che fornisce un po 'di funzionalità extra per consentire ai tuoi modelli di essere estesi da altre estensioni. + + + +### Relazioni + +Puoi aggiungere anche [relazioni](https://laravel.com/docs/6.x/eloquent-relationships) a modelli esistenti utilizzando i metodi `hasOne`, `belongsTo`, `hasMany`, `belongsToMany`e `relationship` sull'estensore `Model`. Il primo argomento è il nome della relazione; il resto degli argomenti viene passato al metodo equivalente sul modello, quindi è possibile specificare il nome del modello correlato e, facoltativamente, sostituire i nomi di tabella e chiave: + +```php + new Extend\Model(User::class) + ->hasOne('phone', 'App\Phone', 'foreign_key', 'local_key') + ->belongsTo('country', 'App\Country', 'foreign_key', 'other_key') + ->hasMany('comment', 'App\Comment', 'foreign_key', 'local_key') + ->belongsToMany('role', 'App\Role', 'role_user', 'user_id', 'role_id') +``` + +Questi 4 dovrebbero coprire la maggior parte delle relazioni, ma a volte è necessaria una personalizzazione più precisa (es. `morphMany`, `morphToMany`, e `morphedByMany`). QUALSIASI relazione Eloquent valida è supportata dal metodo `relationship`: + +```php + new Extend\Model(User::class) + ->relationship('mobile', 'App\Phone', function ($user) { + // Return any Eloquent relationship here. + return $user->belongsToMany(Discussion::class, 'recipients') + ->withTimestamps() + ->wherePivot('removed_at', null); + }) +``` + + +## Serializzatori + +Il passaggio successivo consiste nell'esposizione dei nuovi dati nella JSON: API di Flarum in modo che possano essere utilizzati dal frontend. Dovresti acquisire familiarità con le [specifiche JSON:API](https://jsonapi.org/format/). JSON: API di Flarum è alimentato dalla libreria [tobscure/json-api](https://github.com/tobscure/json-api). + +JSON: le risorse API sono definite da ** serializzatori **. Per definire un nuovo tipo di risorsa, creare una nuova classe serializzatore extendendo `Flarum\Api\Serializer\AbstractSerializer`. Dovrai specificare la risorsa `$type` e implementare il metodo `getDefaultAttributes` che accetta l'istanza del modello come unico argomento: + +```php +use Flarum\Api\Serializer\AbstractSerializer; +use Flarum\Api\Serializer\UserSerializer; + +class DiscussionSerializer extends AbstractSerializer +{ + protected $type = 'discussions'; + + protected function getDefaultAttributes($discussion) + { + return [ + 'title' => $discussion->title, + ]; + } +} +``` + +### Attributi e relazioni + +Puoi anche specificare le relazioni per la tua risorsa. Crea semplicemente un nuovo metodo con lo stesso nome della relazione sul tuo modello e restituisci una chiamata a `hasOne` o `hasMany` a seconda della natura della relazione. È necessario passare l'istanza del modello e il nome del serializzatore da utilizzare per le risorse correlate. + +```php + protected function user($discussion) + { + return $this->hasOne($discussion, UserSerializer::class); + } +``` + +Per aggiungere ** attributi ** e ** relazioni ** a un tipo di risorsa esistente, utilizzare l'estensore `ApiSerializer`: + +```php +use Flarum\Api\Serializer\UserSerializer; + +return [ + (new Extend\ApiSerializer(UserSerializer::class)) + // One attribute at a time + ->attribute('firstName', function ($serializer, $user, $attributes) { + return $user->first_name + }) + // Multiple modifications at once, more complex logic + ->mutate(function($serializer, $user, $attributes) { + $attributes['someAttribute'] = $user->someAttribute; + if ($serializer->getActor()->can('administrate')) { + $attributes['someDate'] = $serializer->formatDate($user->some_date); + } + + return $attributes; + }) + // API relationships + ->hasOne('phone', PhoneSerializer::class) + ->hasMany('comments', CommentSerializer::class), +] +``` + +## API Endpoints + +Dopo aver definito le risorse nei serializzatori, sarà necessario esporle come endpoint API. + +Seguendo le convenzioni dell'API JSON, puoi aggiungere cinque itinerari standard per il tuo tipo di risorsa utilizzando l'estensore `Routes`: + +```php + (new Extend\Routes('api')) + ->get('/tags', 'tags.index', ListTagsController::class) + ->get('/tags/{id}', 'tags.show', ShowTagController::class) + ->post('/tags', 'tags.create', CreateTagController::class) + ->patch('/tags/{id}', 'tags.update', UpdateTagController::class) + ->delete('/tags/{id}', 'tags.delete', DeleteTagController::class) +``` + +Lo spazio dei nomi `Flarum\Api\Controller` contiene un numero di classi astratte che puoi estendere per implementare facilmente le tue risorse JSON-API. + +### Elenco risorse + +Per il controller che elenca la tua risorsa, estendi la classe `Flarum\Api\Controller\AbstractListController`. Come minimo, è necessario specificare quale tipo di `$serializer` vuoi utilizzare per serializzare i tuoi modelli, e implementare `data` per restituire una raccolta di modelli. `data` accetta oggetti `Request` e tobscure/json-api `Document`. + +```php +use Flarum\Api\Controller\AbstractListController; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ListTagsController extends AbstractListController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + return Tag::all(); + } +} +``` + +### Mostra una risorsa + +Per il controller che mostra una singola risorsa, estendi `Flarum\Api\Controller\AbstractShowController`. Come per il controller di elenco, è necessario specificare il `$serializer` che vuoi usare per serializzare i tuoi modelli, implementando `data` per restituire un singolo modello: + +```php +use Flarum\Api\Controller\AbstractShowController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ShowTagController extends AbstractShowController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + return Tag::findOrFail($id); + } +} +``` + +### Creare una risorsa + +Per il controller che crea una risorsa, estendi `Flarum\Api\Controller\AbstractCreateController`. È lo stesso del controller "show", tranne per il fatto che il codice di stato della risposta verrà impostato automaticamente su `201 Created`. È possibile accedere al JSON/corpo del documento API tramite `$request->getParsedBody()`: + +```php +use Flarum\Api\Controller\AbstractCreateController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class CreateTagController extends AbstractCreateController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $attributes = Arr::get($request->getParsedBody(), 'data.attributes'); + + return Tag::create([ + 'name' => Arr::get($attributes, 'name') + ]); + } +} +``` + +### Aggiornare una risorsa + + +Per il controller che aggiorna una risorsa, estendi `Flarum\Api\Controller\AbstractShowController`. Come per il controller di creazione, puoi accedere al corpo del documento JSON:API in entrata tramite `$request->getParsedBody()`. + +### Cancellare una risorsa + +Per il controller che elimina una risorsa, estendi `Flarum\Api\Controller\AbstractDeleteController`. Dovrai solo implementarci `delete` che attua la cancellazione. Il controller restituirà automaticamente un responso `204 No Content`. + +```php +use Flarum\Api\Controller\AbstractDeleteController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; + +class DeleteTagController extends AbstractDeleteController +{ + protected function delete(Request $request) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + Tag::findOrFail($id)->delete(); + } +} +``` + +### Includere Relazioni + +Per includere relazioni quando ** elenchi **, ** mostri ** o ** crei ** la tua risorsa, specificale nelle proprietà del controller con `$include` e `$optionalInclude`: + +```php + // The relationships that are included by default. + public $include = ['user']; + + // Other relationships that are available to be included. + public $optionalInclude = ['discussions']; +``` + +È quindi possibile ottenere un elenco delle relazioni incluse utilizzando `extractInclude`. Questo può essere utilizzato per caricare le relazioni sui modelli prima che questi vengano serializzati: + +```php +$relations = $this->extractInclude($request); + +return Tag::all()->load($relations); +``` + +### Impaginazione + +Puoi consentire la personalizzazione del numero di risorse ** elencate ** specificando nel controlle le proprietà `limit` e `maxLimit`: + +```php + // Il numero di record inclusi per impostazione predefinita. + public $limit = 20; + + // Il numero massimo di record che possono essere richiesti. + public $maxLimit = 50; +``` + +È quindi possibile estrarre le informazioni sull'impaginazione dalla richiesta utilizzando `extractLimit` e `extractOffset`: + +```php +$limit = $this->extractLimit($request); +$offset = $this->extractOffset($request); + +return Tag::skip($offset)->take($limit); +``` + +Per aggiungere collegamenti di impaginazione al documento JSON:API, utilizzare il [`Document::addPaginationLinks` method](https://github.com/tobscure/json-api#meta--links). + +### Ordinamento + +È possibile consentire la personalizzazione dell'ordinamento delle risorse ** elencate ** specificando le proprietà `sort` e `sortField` nel tuo controller: + +```php + // Il campo di ordinamento predefinito e l'ordine da utilizzare. + public $sort = ['name' => 'asc']; + + // I campi disponibili per essere ordinati. + public $sortFields = ['firstName', 'lastName']; +``` + +È quindi possibile estrarre le informazioni sull'ordinamento dalla richiesta utilizzando `extractSort`. Ciò restituirà una serie di criteri di ordinamento che puoi applicare alla tua query: + +```php +$sort = $this->extractSort($request); +$query = Tag::query(); + +foreach ($sort as $field => $order) { + $query->orderBy(snake_case($field), $order); +} + +return $query->get(); +``` + +### Estensione dei controller API + +È possibile personalizzare tutte queste opzioni sul controller _existing_ API tramite `ApiController`: + +```php +use Flarum\Api\Event\WillGetData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->setSerializer(MyDiscussionSerializer::class) + ->addInclude('user') + ->addOptionalInclude('posts') + ->setLimit(20) + ->setMaxLimit(50) + ->setSort(['name' => 'asc']) + ->addSortField('firstName') + ->prepareDataQuery(function ($controller) { + // Add custom logic here to modify the controller + // before data queries are executed. + }) +] +``` + +`ApiController` può essere utilizzato anche per regolare i dati prima della serializzazione: + +```php +use Flarum\Api\Event\WillSerializeData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->prepareDataForSerialization(function ($controller, $data, $request, $document) { + $data->load('myCustomRelation'); + }), +] +``` + +## Modelli frontend + +Ora che hai esposto i tuoi dati nella JSON:API di Flarum, è finalmente giunto il momento di dargli vita e utilizzarli sul frontend. + +### Recupero dati + +Il frontend di Flarum contiene dati locali in `store` che fornisce un'interfaccia per interagire con JSON:API. Puoi recuperare le risorse dall'API utilizzando `find`, che restituisce sempre: + + +```js +// GET /api/discussions?sort=createdAt +app.store.find('discussions', {sort: 'createdAt'}).then(console.log); + +// GET /api/discussions/123 +app.store.find('discussions', 123).then(console.log); +``` + +Una volta che le risorse sono state caricate, verranno memorizzate nella cache nell'archivio in modo da poterle accedere nuovamente senza reiterare l'API utilizzando `all` e `getById`: + +```js +const discussions = app.store.all('discussions'); +const discussion = app.store.getById('discussions', 123); +``` + +Store racchiude i dati delle risorse API non elaborate in oggetti del modello che ne semplificano il lavoro. È possibile accedere ad attributi e relazioni tramite metodi di istanza predefiniti: + +```js +const id = discussion.id(); +const title = discussion.title(); +const posts = discussion.posts(); // array of Post models +``` + +Puoi saperne di più su "store" nella nostra [Documentazione API](https://api.docs.flarum.org/js/master/class/src/common/store.js~store). + +### Aggiunta di nuovi modelli + +Se hai aggiunto un nuovo tipo di risorsa, dovrai definirne un nuovo modello. I modelli devono estendere la classe `Model` e ridefinire gli attributi e le relazioni delle risorse: + + +```js +import Model from 'flarum/Model'; + +export default class Tag extends Model { + title = Model.attribute('title'); + createdAt = Model.attribute('createdAt', Model.transformDate); + parent = Model.hasOne('parent'); + discussions = Model.hasMany('discussions'); +} +``` + +È quindi necessario registrare il nuovo modello presso store: + +```js +app.store.models.tags = Tag; +``` + + + +### Modelli estensibili + +Per aggiungere attributi e relazioni ai modelli esistenti, modificare il prototipo della classe del modello: + +```js +Discussion.prototype.user = Model.hasOne('user'); +Discussion.prototype.posts = Model.hasMany('posts'); +Discussion.prototype.slug = Model.attribute('slug'); +``` + + + +### Risparmio di risorse + +Per inviare di nuovo i dati tramite l'API, chiama il metodo `save` su un'istanza del modello. Questo metodo restituisce un valore che si risolve con la stessa istanza del modello: + +```js +discussion.save({ title: 'Hello, world!' }).then(console.log); +``` + +Puoi anche salvare le relazioni passandole in `relationships`. Per le relazioni singole, passare una singola istanza del modello. Per le relazioni multiple, passare un array di istanze del modello. + +```js +user.save({ + relationships: { + groups: [ + store.getById('groups', 1), + store.getById('groups', 2) + ] + } +}) +``` + +### Creazione di nuove risorse + +Per creare una nuova risorsa, crea una nuova istanza del modello per il tipo di risorsa utilizzando `createRecord`, quindi `save`: + +```js +const discussion = app.store.createRecord('discussions'); + +discussion.save({ title: 'Hello, world!' }).then(console.log); +``` + +### Eliminazione di risorse + +Per eliminare una risorsa, usa `delete` su un'istanza del modello. Questo metodo restituisce: + +```js +discussion.delete().then(done); +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md new file mode 100644 index 000000000..fbfcb948f --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md @@ -0,0 +1,40 @@ +# Distribuzione + +Hai scritto una grande estensione e ora vuoi che il mondo intero sia in grado di usarla. Questo documento ti guiderà attraverso il processo di distribuzione, dalla configurazione di un repository Git per la tua estensione, alla pubblicazione su Packagist. + +## Configurazione di Git + +La prima cosa che devi fare è configurare un sistema di controllo della versione (VCS). Il VCS più popolare è [Git](https://git-scm.com/). In questa guida useremo Git, quindi assicurati di [installarlo](https://git-scm.com/downloads) prima di continuiare. Se non hai molta conoscenza di Git, ti consigliamo di controllare [queste risorse di apprendimento](https://try.github.io/). + +Dopo aver installato Git, dovrai inizializzare il tuo repository. Puoi utilizzare `git init` su riga di comando se ti è più familiare, o un interfaccia tipo [SourceTree](https://www.sourcetreeapp.com/) o [GitKraken](https://www.gitkraken.com/). + +Quindi, avrai bisogno di un account in un server di hosting Git, dove i sovrani sono[GitHub](https://github.com) e [GitLab](https://gitlab.com). Questi siti ti istruiranno su come collegare la tua repository locale con la repository "in remoto" online. + +## Contrassegnare una versione + +Mentre pubblicherai la tua estensione, ti consigliamo di assicurarti che le informazioni siano aggiornate. Prenditi un minuto per rivisitare `composer.json` e assicurati che il nome del pacchetto, la descrizione e le informazioni sull'estensione Flarum siano tutte corrette. Si consiglia di avere un file `README.md` nella tua repository per spiegare qual è e cosa fa l'estensione, quindi creane una se non lo hai già fatto. + +Quando sei pronto per il rilascio, salva i file della tua estensione nel repository e tagga la tua prima versione: + +```bash +git tag v0.1.0 +git push && git push --tags +``` + +## Pubblicazione su Packagist + +I pacchetti Composer sono pubblicati in una repository, solitamente [Packagist](https://packagist.org/). Avrai bisogno di un account per proseguire. + +Se questa è la prima versione della tua estensione che stai pubblicando, [carica il tuo pacchetto](https://packagist.org/packages/submit) utilizzando il suo URL repository pubblico. Se la tua estensione si trova su GitHub, questo URL avrà un aspetto simile `https://github.com/AUTHOR/NAME.git`. + +### Rilasci futuri + +Puoi configurare Packagist per [auto-aggiornare i pacchetti](https://packagist.org/about#how-to-update-packages). Quindi, per le versioni future, tutto ciò che dovrai fare con Git è eseguire il commit, il tag e il push al server remoto. + +## Promuovere la tua estensione + +Molto probabilmente vorrai creare una discussione sulla comunità Flarum sulla categoria [Estensioni](https://discuss.flarum.org/t/extensions). Altre persone potranno installare la tua estensione utilizzando il seguente comando: + +```bash +composer require autore/nome-estensione +``` \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md new file mode 100644 index 000000000..e91d4bf11 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md @@ -0,0 +1,122 @@ +# Estendere le Estensioni + +Le estensioni di Flarum non prevedono solo l'aggiunta di funzionalità al core: le estensioni possono estendere anche altre estensioni! + +:::tip + +Per imparare a rendere estensibile la tua estensione, consulta la [documentazione pertinente](extensibility.md) + +::: + +## Dipendenze + +Se la tua estensione si basa su un'altra estensione, ti assicurerai che: + +- L'altra estensione è installata e abilitata prima della tua attuale estensione. +- L'altra estensione non può essere disabilitata mentre la tua è abilitata. +- L'altra estensione viene avviata prima della tua estensione. + +Flarum rende tutto ciò molto facile: basta aggiungere l'altra estensione al file `composer.json`della tua estensione o nella sezione `require`. + +Ad esempio, se stai sviluppando un nuovo tema per l'estensione Tag Flarum, il tuo `composer.json` dovrebbe essere simile a questo: + +```json +{ + // ... + "require": { + "flarum/core": "^1.0.0", // Perchè tutte le estensioni necessitano del Core di Flarum. + "flarum/tags": "^1.1.0" // Questo dice a Flarum di trattare i tag come dipendenza della tua estensione. + }, + // ... +} +``` + +## Dipendenze opzionali + +A volte, l'estensione A potrebbe voler estendere l'estensione B solo se l'estensione B è abilitata. In questo caso, chiamiamo B una "Dipendenza opzionale" di A. Per esempio, l'estensione "Drafts" potrebbe voler aggiungere il supporto per salvare bozze di discussione private, ma solo se l'estensione di discussione privata è abilitata. + +Il primo passo quindi è quello di rilevare se l'estensione B è abilitata. Nel frontend, è facile: se l'estensione B fa qualcosa nel frontend, il suo ID di estensione apparirà come chiave nell'oggetto globale `flarum.extensions` . Per esempio: + +```js +if ('some-extension-id' in flarum.extensions) { + // fai qualcosa +} +``` + +Nel backend, dovrai iniettare un'istanza di `Flarum\Extension\ExtensionManager`e usare il metodo `isEnabled()`. Per esempio: + +```php +extensions = $extensions; + } + + public function someMethod() + { + if ($this->extensions->isEnabled('some-extension-id')) { + // fai qualcosa. + } + } +} +``` + +Generalmente, se la tua estensione ha dipendenze opzionali, vorrai che venga avviata dopo queste dipendenze opzionali. Tutto ciò è possibile farlo anche specificando i nomi dei pacchetti composer (NON ID dell' estensione flarum) in un array `extra.flarum-extension.optional-dependencies` del tuo file composer.json. + +Per esempio: + +```json +{ + // ... + "extra": { + "flarum-extension": { + "optional-dependencies": [ + "flarum/tags" + ] + } + }, + // ... +} +``` + +## Importazione da estensioni + +Nel backend, puoi importare le classi di cui hai bisogno tramite la dichiarazione PHP `use`: + +```php + { + // Il codice della tua estensione andrà qui +}) + +export { + // Tutto ciò che vuoi esportare invece andrà qui. +} +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md new file mode 100644 index 000000000..455663d4a --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md @@ -0,0 +1,129 @@ +# Filesystem + +Flarum core si integra con il filesystem per memorizzare e servire asset (come JS/CSS compilato o caricare loghi/favicon) e avatar. + +Le estensioni possono utilizzare le utilità fornite da Flarum per le proprie interazioni con il filesystem e le esigenze di archiviazione dei file. Questo sistema si basa sugli strumenti del [filesystem di Laravel](https://laravel.com/docs/8.x/filesystem), che a loro volta si basano sulla libreria [Flysystem](https://github.com/thephpleague/flysystem). + +## Dischi + +I dischi **del filesystem** rappresentano le posizioni di archiviazione e sono supportati da driver di archiviazione, che approfondiremo più tardi. Flarum core ha 2 dischi: `flarum-assets` e `flarum-avatars`. + +### Utilizzo dei dischi esistenti + +Per accedere a un disco, è necessario recuperarlo dalla [Filesystem Factory](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Factory.html). Per farlo, dovresti iniettare il factory contract nella tua classe e accedere ai dischi di cui hai bisogno. + +Let's take a look at core's [`DeleteLogoController`](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Controller/DeleteLogoController.php#L19-L58) for an example: + +```php +settings = $settings; + $this->uploadDir = $filesystemFactory->disk('flarum-assets'); + } + + /** + * {@inheritdoc} + */ + protected function delete(ServerRequestInterface $request) + { + RequestUtil::getActor($request)->assertAdmin(); + + $path = $this->settings->get('logo_path'); + + $this->settings->set('logo_path', null); + + if ($this->uploadDir->exists($path)) { + $this->uploadDir->delete($path); + } + + return new EmptyResponse(204); + } +} +``` + +L'oggetto restituito da `$filesystemFactory->disk(DISK_NAME)` implementa l'interfaccia [Illuminate\Contracts\Filesystem\Cloud](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Cloud.html), e può essere utilizzato per creare/ottenere/spostare/eliminare file, e per ottenere l'URL di una risorsa. + +### Dichiarazione di nuovi dischi + +Alcune estensioni però potrebbero voler immagazzinare risorse/upload su un disco personalizzato invece di utilizzare `flarum-asset` o `flarum-avatars`. + +Questo può essere fatto tramite l'extender `Filesystem`: + +```php +use Flarum\Extend; + +return [ + (new Extend\Filesystem) + ->disk('flarum-uploads', function (Paths $paths, UrlGenerator $url) { + return [ + 'root' => "$paths->public/assets/uploads", + 'url' => $url->to('forum')->path('assets/uploads') + ]; + }); +``` + +Poiché tutti i dischi usano il filesystem locale per impostazione predefinita, è necessario fornire un percorso di base e un URL di base per il filesystem locale. + +L'array di configurazione può contenere altre voci supportate da [Array di configurazione dischi Laravel](https://laravel.com/docs/8.x/filesystem#configuration). La chiave `driver` non deve essere fornita, e verrà comunque ignorata. + +## Storage drivers + +Flarum seleziona il driver attivo per ogni disco controllando il `disk_driver.DISK_NAME` in [settings repository](settings.md) e [config.php](../config.md). Se nessun driver è configurato, o il driver configurato non è disponibile, Flarum utilizzerà il driver `local`. + +You can define new storage drivers by implementing the [`Flarum\Filesystem\DriverInterface` interface](https://github.com/flarum/framework/blob/main/framework/core/src/Filesystem/DriverInterface.php#L16), and registering it via the `Filesystem` extender: + +```php +use Flarum\Extend; + +return [ + (new Extend\Filesystem) + ->driver('aws-with-cdn', AwsWithCdnDriver::class); +``` + +I driver di archiviazione del filesystem sono uno strumento molto potente che consente di personalizzare completamente le posizioni di archiviazione dei file, allegare CDN arbitrari, ed estendere il filesystem/cloud storage. + +:::Attenzione + +Alcuni driver potrebbero provare a indicizzare il loro filesystem ogni volta che il driver viene istanziato, anche se è necessario solo il metodo `url`. Ciò può avere gravi ripercussioni sulle prestazioni. Nella maggior parte dei casi, dovrai assicurarti che il metodo `url` del tuo driver non esegua il filesystem remoto. Allo stesso modo, il filesystem remoto di solito non dovrebbe essere accessibile fino a quando le operazioni non vengono effettivamente eseguite. + +::: + +## Configurazione interfaccia utente e amministratore + +Flarum al momento non fornisce una GUI per selezionare driver o per inserire impostazioni per i driver. Ma potrebbe essere aggiunta in futuro. Per ora, le estensioni sono responsabili di fornire una GUI per i loro dischi/driver. + +Come notato [sopra](#storage-drivers), se la tua estensione fornisce una GUI per selezionare driver di un disco, dovrà modificare il `disk_driver.DISK_NAME` nelle impostazioni. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md new file mode 100644 index 000000000..41d5e867e --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md @@ -0,0 +1,42 @@ +# Formattazione + +Flarum usa la potente libreria [s9e TextFormatter](https://github.com/s9e/TextFormatter) per formattare i post dal semplice markup in HTML. Dovresti familiarizzare con [come funziona TextFormatter](https://s9etextformatter.readthedocs.io/Getting_started/How_it_works/) prima di utilizzarlo. + +In Flarum, il contenuto del post è formattato con una configurazione TextFormatter minima per impostazione predefinita. Le estensioni ** Markdown ** e ** BBCode ** in bundle abilitano semplicemente i rispettivi plugin. + +## Configurazione + +Puoi configurare l'istanza di TextFormatter `Configurator`, così come eseguire la logica personalizzata durante l'analisi e il rendering, utilizzando l'estensione `Formatter`: + +```php +use Flarum\Extend; +use Psr\Http\Message\ServerRequestInterface as Request; +use s9e\TextFormatter\Configurator; +use s9e\TextFormatter\Parser; +use s9e\TextFormatter\Renderer; + +return [ + (new Extend\Formatter) + // Aggiungi la configurazione del formattatore di testo personalizzato + ->configure(function (Configurator $config) { + $config->BBCodes->addFromRepository('B'); + }) + // Modifica il testo grezzo prima che venga analizzato. + // Questa callback dovrebbe restituire il testo modificato. + ->parse(function (Parser $parser, $context, $text) { + // logica personalizzata qui + return $newText; + }) + //Modificare l'XML di cui eseguire il rendering. + // il suo callback dovrebbe restituire il nuovo XML. + // Ad esempio, nell'estensione menzioni, viene utilizzato per + // fornire il nome utente e il nome visualizzato dell'utente menzionato. + // Assicurati che l'ultimo argomento $request sia annullabile (o omesso completamente). + ->render(function (Renderer $renderer, $context, $xml, Request $request = null) { + // logica personalizzata qui + return $newXml; + }) +]; +``` + +Una buona conoscenza di TextFormatter, ti consentirà di ottenere molti risultati, dalle semplici aggiunte di tag BBCode a compiti di formattazione più complessi come l'estensione ** Mentions ** di Flarum. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/forms.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/forms.md new file mode 100644 index 000000000..3d07c86ef --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/forms.md @@ -0,0 +1,108 @@ +# Moduli e richieste + +In questo articolo, esamineremo alcuni strumenti di frontend che sono a nostra disposizione per la creazione e la gestione di moduli, nonché come inviare richieste HTTP tramite Flarum. + +## Componenti Form + +Come con qualsiasi sito interattivo, probabilmente vorrai includere moduli in alcune pagine. Flarum fornisce alcuni componenti per rendere più facile la costruzione (e lo styling!) di questi ultimi. Si prega di consultare la documentazione API collegata per per saperne di più sugli attributi accettati. + +- Il [`flarum/components/FieldSet` componente](https://api.docs.flarum.org/js/master/class/src/common/components/fieldset.js~fieldset) racchiude i suoi "figli" in un tag fieldset HTML, con una legenda. +- Il [`flarum/components/Select` componente](https://api.docs.flarum.org/js/master/class/src/common/components/select.js~select) è un input di selezione stilizzato. +- [`flarum/components/Switch`](https://api.docs.flarum.org/js/master/class/src/common/components/switch.js~switch) e [`flarum/components/Checkbox` i componenti](https://api.docs.flarum.org/js/master/class/src/common/components/checkbox.js~checkbox) sono componenti di input delle caselle di controllo stilizzate. Il loro attributo `loading` può essere impostato su `true` per mostrare un indicatore di caricamento. +- Il componente [`flarum/components/Button`](https://api.docs.flarum.org/js/master/class/src/common/components/button.js~button) è un bottone stilizzato, frequentemente utilizzato su Flarum. + +In genere vorrai assegnare la logica per reagire ai cambiamenti di input tramite Mithril e l'attributo `on*`, non listener esterni (come è comune con jQuery o semplice JS). Per esempio: + +```jsx +import Component from 'flarum/Component'; +import FieldSet from 'flarum/components/FieldSet'; +import Button from 'flarum/components/Button'; +import Switch from 'flarum/components/Switch'; + + +class FormComponent extends Component { + oninit(vnode) { + this.textInput = ""; + this.booleanInput = false; + } + + view() { + return ( +
+
+ this.textInput = e.target.value}> + + this.booleanInput = val}> + +
+ +
+ ) + } + + onsubmit() { + // Some form handling logic here + } +} +``` + +Don't forget to use [translations](translate.md)! + + +## Streams, bidi, e withAttr + +Flarum provides [Mithril's Stream](https://mithril.js.org/stream.html) as `flarum/util/Stream`. Questa è una struttura di dati molto potente, ma è più comunemente usata in Flarum come wrapper per i dati dei moduli form. Il suo utilizzo di base è: + +```js +import Stream from 'flarum/utils/Stream'; + + +const value = Stream("hello!"); +value() === "hello!"; // true +value("world!"); +value() === "world!"; // true +``` + +Nei form di Flarum, i flussi sono spesso usati insieme all'attributo bidi. Bidi sta per associazione bidirezionale ed è un modello comune nei framework di frontend. Flarum applica al Mithril la [`m.attrs.bidi` libreria](https://github.com/tobyzerner/m.attrs. Questo astrae l'elaborazione degli input in Mithril. Per esempio: + +```jsx +import Stream from 'flarum/utils/Stream'; + +const value = Stream(); + +// Without bidi + value(e.target.value)}> + +// With bidi + +``` + +You can also use the `flarum/utils/withAttr` util for simplified form processing. `withAttr` chiama un callable, fornendo come argomento qualche attr dell'elemento DOM legato al componente in questione: + +```jsx +import Stream from 'flarum/utils/Stream'; +import withAttr from 'flarum/utils/withAttr'; + +const value = Stream(); + +// With a stream + + +// With any callable + { + // Some custom logic here +})}> +``` + +## Effettuare richieste + +Nella nostra [documentazione di modelli e dati](data.md), hai imparato come lavorare con i modelli e salvare la creazione del modello, le modifiche e l'eliminazione nel database tramite l'utilità Store, che è solo un wrapper attorno al sistema di richiesta di Flarum, che a sua volta è un altro wrapper [Sistema di richieste Mithril](https://mithril.js.org/request.html). + +Il sistema di richiesta di Flarum è disponibile a livello globale tramite `app.request(options)`, e presenta le seguenti differenze rispetto a Mithril `m.request(options)`: + +- Si legherà automaticamente all'header `X-CSRF-Token`. +- Convertirà richieste `PATCH` e `DELETE` in richieste `POST`, e si legherà all'heder `X-HTTP-Method-Override`. +- In caso di errore della richiesta, verrà visualizzato un avviso che, se in modalità debug, può essere cliccato per mostrare un modale di errore completo. +- Puoi fornire anche l'opzione `background: false`, che eseguirà la richiesta in modo sincrono. Tuttavia, questo non dovrebbe quasi mai essere fatto. + +Altrimenti, l'API per l'utilizzo `app.request` è la medesima di `m.request`. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md new file mode 100644 index 000000000..234ceff95 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md @@ -0,0 +1,226 @@ +# Frontend e Resolver + +Come spiegato nella documentazione [percorsi e contenuti](routes.md#frontend-routes), possiamo usare il sistema di routing di Mithril per mostrare diversi [componenti](frontend.md#components) per differenti percorsi. Mithril ti consente di utilizzare qualsiasi componente che ti piace, anche un Modal o Alert, ma ti consigliamo di attenersi alle classi di componenti che ereditano il componente `Page`. + +## I componenti Page + +Forniamo `flarum/components/Page` come classe base per le pagine sia in `admin` che nel frontend di `forum`. Questi i vantaggi: + +- Aggiornamenti automatici di [`app.current` e `app.previous` PageState](#pagestate) quando si passa da un percorso ad un altro. +- Chiude automaticamente il modal quando si passa da un percorso a un altro. +- Si applica `this.bodyClass` (se definito) all'elemento HTML "#app" quando la pagina viene visualizzata. +- È anche utile per motivi di coerenza utilizzare una classe base comune per tutte le pagine. +- Se l'attributo delle pagine `scrollTopOnCreate` è impostato su `false` in `oninit`, la pagina non verrà spostata verso l'alto quando viene modificata. +- Se `useBrowserScrollRestoration` è impostato su `false` in `oninit`, il ripristino dello scorrimento automatico del browser non verrà utilizzato su quella pagina. + +I componenti della pagina funzionano esattamente come qualsiasi altro componente ereditato. Per esempio (molto semplice): + +```js +import Page from 'flarum/components/Page'; + + +export default class CustomPage extends Page { + view() { + return

Hello!

+ } +} +``` + +### Usare i Route Resolvers + +Flarum utilizza un'impostazione per determinare quale pagina dovrebbe essere la homepage: questo dà flessibilità agli amministratori per personalizzare le loro community. Per aggiungere una pagina personalizzata alla homepage in Admin, è necessario estendere il metodo `BasicsPage.homePageItems` con il percorso della tua nuova pagina. + +I dati possono essere impostati e recuperati dallo stato della pagina utilizzando: + +```js +import IndexPage from 'flarum/components/DiscussionPage'; +import DiscussionPage from 'flarum/components/DiscussionPage'; + +// To just check page type +app.current.matches(DiscussionPage); + +// To check page type and some data +app.current.matches(IndexPage, {routeName: 'following'}); +``` + +Ad esempio, questo è il modo in cui la pagina di discussione fa la sua istanza di [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) disponibile a livello globale. + +### Resolvers personalizzati + +Spesso, la prima cosa che si modifica è il testo personalizzato che appare nel titolo della scheda del browser. Per esempio, una pagina di tag potrebbe voler mostrare "Tag - NOME FORUM", o una pagina di discussione potrebbe voler mostrare il titolo della discussione. + +Per fare ciò, dovrai aggiungere alla tua pagina la call `app.setTitle()` e `app.setTitleCount()` nel metodo `oncreate` del [lifecycle hook](frontend.md) (o quando i dati sono stati caricati, se richiesti tramite API). + +In realtà ci sono 3 modi per impostare il resolver di componenti / percorsi durante la registrazione di una route: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + oncreate(vnode) { + super.oncreate(vnode); + + app.setTitle("Cool Page"); + app.setTitleCount(0); + } + + view() { + // ... + } +} + +export default class CustomPageLoadsData extends Page { + oninit(vnode) { + super.oninit(vnode); + + app.store.find("users", 1).then(user => { + app.setTitle(user.displayName()); + app.setTitleCount(0); + }) + } + + view() { + // ... + } +} +``` + +Si prega di notare che se la pagina è [impostata come homepage](#setting-page-as-homepage), `app.setTitle()` cancellerà il titolo per semplicità. Dovrebbe comunque essere impostato, per evitare che i titoli delle pagine precedenti vengano applicati. + +## PageState + +A volte, vogliamo ottenere informazioni sulla pagina in cui ci troviamo attualmente o sulla pagina da cui proveniamo. Per consentire ciò, Flarum crea (e memorizza) istanze di [`PageState`](https://api.docs.flarum.org/js/master/class/src/common/states/pagestate.js~pagestate) come `app.current` e `app.previous`. Cioè: + +- La classe del componente utilizzata per la pagina +- Una raccolta di dati che ogni pagina imposta su se stessa. Il nome della rotta corrente è sempre incluso. + +I dati possono essere impostati e recuperati da Page State utilizzando: + +```js +app.current.set(KEY, DATA); +app.current.get(KEY); +``` + +Ad esempio, ecco come la Pagina di Discussione rende [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) disponibile globalmente. + +Puoi anche controllare il tipo e i dati di una pagina usando `PostStreamState` ed il metodo `matches`. Ad esempio, se vogliamo sapere se siamo attualmente su una pagina di discussione: + +```jsx +// Vedi sopra per un esempio di pagina personalizzata +import CustomPage from './components/CustomPage'; +// Vedi sotto per un esempio di resolver personalizzato +import CustomPageResolver from './resolvers/CustomPageResolver'; + +// Utilizza un'istanza del resolver di percorsi +app.routes['resolverInstance'] = {path: '/custom/path/1', resolver: { + onmatch: function(args) { + if (!app.session.user) return m.route.SKIP; + + return CustomPage; + } +}}; + +// Usa una classe di resolver di percorsi personalizzata +app.routes['resolverClass'] = {path: '/custom/path/2', resolverClass: CustomPageResolver, component: CustomPage}; + +// Usa la classe di default (`flarum/resolvers/DefaultResolver`) +app.routes['resolverClass'] = {path: '/custom/path/2', component: CustomPage}; +``` + +## Route resolver (avanzato) + +Vedi la documentazione [Pannello di amministrazione](admin.md) per ulteriori informazioni sugli strumenti disponibili per le pagine di amministrazione (e su come sovrascrivere la pagina di amministrazione per la tua estensione). + +## Route Resolvers (Avanzato) + +[Casi d'uso avanzati](https://mithril.js.org/route.html#advanced-component-resolution) possono ottenere vantaggi dal [sistema di risoluzione dei percorsi di Mithril](https://mithril.js.org/route.html#routeresolver). Flarum in realtà avvolge già tutti i suoi componenti nel resolver `flarum/resolvers/DefaultResolver`. Ciò ha i seguenti vantaggi: + +- Passa un attributo `routeName` alla pagina corrente, che poi lo fornisce a`PageState` +- Assegna una [chiave](https://mithril.js.org/keys.html#single-child-keyed-fragments) al componente della pagina di primo livello. Quando il percorso cambia, se la chiave del componente di primo livello è cambiata, verrà riprodotto completamente (per impostazione predefinita, Mithril non esegue il rendering dei componenti quando si passa da una pagina all'altra se entrambi sono gestiti dallo stesso componente). + +### Usare i Route Resolvers + +Ci sono in realtà 3 modi per impostare il componente/route resolver durante la registrazione di un nuovo percorso: + +- la chiave `resolver` può essere usata per fornire un ** istanza ** di un risolutore di percorsi. Questa istanza dovrebbe definire quale componente deve essere utilizzato e codificare il nome del percorso da passare al suo interno. Questa istanza verrà utilizzata senza alcuna modifica da Flarum. +- Le chiavi `resolverClass` e `component` possono essere usate per fornire una ** classe ** che sarà utilizzata per istanziare un risolutore di percorsi, da usare al posto di quella predefinita di Flarum, così come il componente da usare. Il suo costrutto dovrebbe avere 2 argomenti: `(component, routeName)`. +- La chiave `component` può essere usata da sola per un componente. Ciò comporterà un comportamento predefinito. + +Per esempio: + +```js +//Guarda in alto per le pagine personalizzate +import CustomPage from './components/CustomPage'; +// Guarda in basso per i resolver personalizzati di esempio +import CustomPageResolver from './resolvers/CustomPageResolver'; + +// Usa un route resolver +app.routes['resolverInstance'] = {path: '/custom/path/1', resolver: { + onmatch: function(args) { + if (!app.session.user) return m.route.SKIP; + + return CustomPage; + } +}}; + +// Utilizza un resolver personalizzato +app.routes['resolverClass'] = {path: '/custom/path/2', resolverClass: CustomPageResolver, component: CustomPage}; + +// Usa la classe di default (`flarum/common/resolvers/DefaultResolver`) +app.routes['resolverClass'] = {path: '/custom/path/2', component: CustomPage}; +``` + +### Resolver Personalizzati + +Consigliamo vivamente di estendere i risolutori di percorsi personalizzati `flarum/resolvers/DefaultResolver`. Per esempio, Flarum `flarum/resolvers/DiscussionPageResolver` assegna la stessa chiave a tutti i collegamenti alla stessa discussione (indipendentemente dal post corrente) e attiva lo scorrimento quando si utilizza `m.route.set` per passare da un post all'altro nella stessa pagina di discussione: + +```js +import DefaultResolver from '../../common/resolvers/DefaultResolver'; + +/** + * Non viene esportato in quanto si tratta di una misura temporanea. + * Un sistema più robusto verrà implementato insieme al supporto UTF-8 nella beta 15. + */ +function getDiscussionIdFromSlug(slug: string | undefined) { + if (!slug) return; + return slug.split('-')[0]; +} + +/** + * Un risolutore di percorsi personalizzato per DiscussionPage che genera la stessa chiave per tutti i post + * nella stessa discussione. Attiva uno scorrimento quando si passa da un post all'altro + * nella stessa discussione. + */ +export default class DiscussionPageResolver extends DefaultResolver { + static scrollToPostNumber: number | null = null; + + makeKey() { + const params = { ...m.route.param() }; + if ('near' in params) { + delete params.near; + } + params.id = getDiscussionIdFromSlug(params.id); + return this.routeName.replace('.near', '') + JSON.stringify(params); + } + + onmatch(args, requestedPath, route) { + if (route.includes('/d/:id') && getDiscussionIdFromSlug(args.id) === getDiscussionIdFromSlug(m.route.param('id'))) { + DiscussionPageResolver.scrollToPostNumber = parseInt(args.near); + } + + return super.onmatch(args, requestedPath, route); + } + + render(vnode) { + if (DiscussionPageResolver.scrollToPostNumber !== null) { + const number = DiscussionPageResolver.scrollToPostNumber; + // Scroll after a timeout to avoid clashes with the render. + setTimeout(() => app.current.get('stream').goToNumber(number)); + DiscussionPageResolver.scrollToPostNumber = null; + } + + return super.render(vnode); + } +} +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md new file mode 100644 index 000000000..9cc8aa444 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md @@ -0,0 +1,502 @@ +# Sviluppo del Frontend + +Questa pagina descrive come apportare modifiche all'interfaccia utente di Flarum. Come aggiungere pulsanti, cornici e testo lampeggiante. 🤩 + +[Ricorda](/extend/start.md#architecture), Il frontend di Flarum � un ** applicazione JavaScript a pagina singola **. Non ci sono Twig, Blade o qualsiasi altro tipo di modelli PHP di cui parlare. I pochi modelli presenti nel back-end vengono utilizzati solo per il rendering di contenuto ottimizzato per i motori di ricerca. Tutte le modifiche all'interfaccia utente devono essere apportate tramite JavaScript. + +Flarum ha due applicazioni frontend separate: + +* `forum`, la parte pubblica del forum in cui gli utenti creano discussioni e post. +* `admin`, il lato privato del tuo forum dove, come amministratore del tuo forum, configuri la tua installazione di Flarum. + +Condividono lo stesso codice di base, quindi una volta che sai come estenderne uno, sai come estenderli entrambi. + +:::tip Typings! + +Insieme al nuovo supporto TypeScript, abbiamo un pacchetto [`tsconfig`](https://www.npmjs.com/package/flarum-tsconfig) disponibile, che si dovrebbe installare come dipendenza per ottenere accesso ai nostri typings durante lo sviluppo. Assicurati di seguire le istruzioni contenute nel README del pacchetto + + per configurare il supporto ai typings. + +::: + + + +## Struttura dei File + +Questa parte della guida spiegher� la configurazione dei file necessaria per le estensioni. Ancora una volta, consigliamo vivamente di utilizzare [FoF extension generator (non ufficiale)](https://github.com/FriendsOfFlarum/extension-generator) per impostare la struttura di base per te. Detto questo, dovresti comunque leggere questa guida per capire cosa accade sotto la superficie. + +Prima di poter scrivere qualsiasi JavaScript, dobbiamo impostare un **transpiler**. Questo ti permetter� di utilizzare [TypeScript](https://www.typescriptlang.org/) e la sua magia nel nucleo e nelle estensioni di Flarum. + +Per fare ci�, devi lavorare in un ambiente adatto. No, non il tipo di ambiente di casa/ufficio - puoi lavorare in bagno per quel che ci importa! Stiamo parlando degli strumenti installati sul tuo sistema. Avrai bisogno: + +* Node.js e npm ([Download](https://nodejs.org/en/download/)) +* Webpack (`npm install -g webpack`) + +Questo pu� essere complicato perch� il sistema di ognuno � diverso. Dal sistema operativo che stai utilizzando, alle versioni del programma che hai installato, alle autorizzazioni di accesso dell'utente – Ci vengono i brividi solo a pensarci! Se incappi nei guai, ~~ti salutiamo~~ usa [Google](https://google.com) per vedere se qualcuno ha riscontrato il tuo stesso errore e ha trovato una soluzione. In caso contrario, chiedi aiuto nel [Forum di Flarum](https://flarumit.it) o su [Discord chat](https://flarum.org/discord/). + +� ora di impostare il nostro piccolo progetto di traspilazione JavaScript. Crea una nuova cartella nella tua estensione chiamata `js`, quindi inserisci un paio di nuovi file. Una tipica estensione avr� la seguente struttura di frontend: + + + +``` +js +├── dist (compiled js is placed here) +├── src +│ ├── admin +│ └── forum +├── admin.js +├── forum.js +├── package.json +└── webpack.config.json +``` + + + + +### package.json + + + +```json +{ + "private": true, + "name": "@acme/flarum-hello-world", + "dependencies": { + "flarum-webpack-config": "0.1.0-beta.10", + "webpack": "^4.0.0", + "webpack-cli": "^3.0.7" + }, + "scripts": { + "dev": "webpack --mode development --watch", + "build": "webpack --mode production" + } +} +``` + + +Questo � un [pacchetto](https://docs.npmjs.com/files/package.json) standard di JS, usato da npm e Yarn (Gestori di pacchetto javascript). Puoi usarlo per aggiungere comandi, dipendenze js e metadati del pacchetto. In realt� non stiamo pubblicando un pacchetto npm: questo � semplicemente usato per raccogliere le dipendenze. + +Si prega di notare che non � necessario includere `flarum/core` o qualsiasi estensione flarum come dipendenze: verranno automaticamente pacchettizzate quando Flarum compila i frontend per tutte le estensioni. + + + +### webpack.config.js + + + +```js +const config = require('flarum-webpack-config'); + +module.exports = config(); +``` + + +[Webpack](https://webpack.js.org/concepts/) � il sistema che effettivamente compila e raggruppa tutto il javascript (e le sue dipendenze) per la nostra estensione. Per funzionare correttamente, le nostre estensioni dovrebbero utilizzare il [Webpack ufficiale di configurazione Flarum](https://github.com/flarum/flarum-webpack-config) (mostrato nell'esempio sopra). + + + +### admin.js e forum.js + + + +```json +{ + // Usa il tsconfig di Flarum come punto di partenza + "extends": "flarum-tsconfig", + // Questo corrisponderà a tutti . s, .tsx, .d.ts, .js, . file sx nella tua cartella `src` + // e dice anche al tuo server Typescript di leggere i typings globali del core per + // l'accesso a `dayjs` e `$` nel namespace globale. + "include": ["src/**/*", "../vendor/flarum/core/js/dist-typings/@types/**/*"], + "compilerOptions": { + // This will output typings to `dist-typings` + "declarationDir": "./dist-typings", + "baseUrl": ".", + "paths": { + "flarum/*": ["../vendor/flarum/core/js/dist-typings/*"] + } + } +} +``` + + +Questo è una configurazione standard per abilitare il supporto aTypescript con le opzioni di cui Flarum ha bisogno. + +Assicurati sempre di usare l'ultima versione del file: https://github.com/flarum/flarum-tsconfig#readme. + +Di seguito esamineremo gli strumenti disponibili per le estensioni. + +Per far funzionare i typings, dovrai eseguire `composer update` nella cartella delle tue estensioni per scaricare l'ultima copia del core di Flarum in una nuova cartella `vendor`. Ricordati di non eseguire il commit di questa cartella se stai usando un sistema come Git. + +Potrebbe essere necessario anche riavviare il server TypeScript dell'IDE. In Visual Studio Code, è possibile premere F1, quindi digitare "Riavvia TypeScript Server" e premere INVIO. Potrebbe richiedere qualche minuto per il suo completamento. + + + +### admin.js e forum.js + +Questi file contengono la radice del nostro JS di frontend effettivo. Potresti mettere qui l'intera estensione, ma non sarebbe ben organizzata. Per questo motivo, consigliamo di inserire il codice sorgente attuale in `src`, e avendo questi file solo esportare il contenuto di `src`. Per esempio: + + + +```js +// admin.js +export * from './src/admin'; + +// forum.js +export * from './src/forum'; +``` + + + + +### src + +Se si seguono le raccomandazioni per `admin.js` e `forum.js`, dovremmo avere 2 sottocartelle: una per il codice frontend di `admin`, ed una per il frontend fi `forum`. Se disponi di componenti, modelli, utilit� o altro codice condiviso tra entrambi i frontend, potresti voler creare un file `common` in una sottocartella. + +La struttura per `admin` e `forum` � identica, vi mostriamo quella di `forum` qui: + + + +``` +src/forum/ +├── components/ +|-- models/ +├── utils/ +└── index.js +``` + + +`components`, `models`, e `utils` sono directory che contengono file in cui � possibile definire [componenti personalizzati](#components), [modelli](data.md#frontend-models), e funzioni utili riutilizzabili. Tieni presente che questo � semplicemente un consiglio: non c'� nulla che ti costringa a utilizzare questa particolare struttura di file (o qualsiasi altra struttura di file). + +Il file pi� importante qui � `index.js`: tutto il resto � solo l'estrazione di classi e funzioni nei propri file. Esaminiamo un tipico `index.js`: + + + +```js +import {extend, override} from 'flarum/extend'; + +// We provide our extension code in the form of an "initializer". +// Questa è una callback che verrà eseguita dopo che il core è stato avviato. +app.initializers.add('our-extension', function(app) { + // Your Extension Code Here + console.log("EXTENSION NAME is working!"); +}); +``` + + +Vedremo gli strumenti disponibili per le estensioni qui sotto. + + + +### Transpilazione + +:::tip Librerie esterne + +Praticamente ogni estensione Flarum dovr� importare * qualcosa * da Flarum Core. Come la maggior parte delle estensioni, il codice sorgente JS di core � suddiviso in cartelle `admin`, `common`, e `forum`. Tuttavia, viene esportato tutto in `flarum`. Per elaborare: + +In alcuni casi, un'estensione potrebbe voler estendere il codice da un'altra estensione flarum. Questo � possibile solo per le estensioni che esportano esplicitamente il loro contenuto. + +* `flarum/tags` e `flarum/flags` sono attualmente le uniche estensioni in bundle che consentono di estendere il proprio JS. Puoi importare i loro contenuti da `flarum/{EXT_NAME}/PATH` (es. `flarum/tags/components/TagHero`). +* Il processo per estendere i plugin della community è diverso; è necessario consultare la documentazione per ogni singola estensione. + + + +### Transpilazione + +OK, � ora di accendere il transpiler. Esegui i seguenti comandi nella directory `js`: + + + +```bash +npm install +npm run dev +``` + + +Questo compilerà il tuo codice JavaScript pronto per il browser nel file `js/dist/forum.js`, e continuerà a compilarne le modifiche ai file di origine in tempo reale. Carino! + +Quando hai finito di sviluppare la tua estensione (o prima di una nuova versione), ti consigliamo di eseguire `npm run build` invece di `npm run dev`: questo crea l'estensione in modalità di produzione, che renderà il codice sorgente più snello e più veloce. + + + +## Registrazione Asset + + + +### JavaScript + +Affinché il JavaScript della tua estensione possa essere caricato nel frontend, dobbiamo dire a Flarum dove trovarlo. Possiamo farlo usando l'extender `Frontend` e metodo `js`. Aggiungilo alla tua estensione nel file `extend.php`: + + + +```php +js(__DIR__.'/js/dist/forum.js') +]; +``` + + +Flarum renderà tutto ciò che esporti con `export` da `forum.js` disponibile nell'oggetto `flarum.extensions['acme-hello-world']`. Inoltre, puoi scegliere di esporre la tua API pubblica per consentire ad altre estensioni di interagire. + +:::tip Librerie Esterne + +È consentito solo un file JavaScript principale per estensione. Se è necessario includere una libreria JavaScript esterna, è possibile sia installarla con NPM e `import` in modo che siano compilati nel tuo file JavaScript, o vedi [Percorsi e Contenuti](/extend/routes.md) per imparare ad aggiungere tag aggiuntivi `'; + }) +]; +``` + +You can also add content onto your frontend route registrations: + +```php +return [ + (new Extend\Frontend('forum')) + ->route('/users', 'acme.users', function (Document $document, Request $request) { + $document->title = 'Users'; + }) +]; +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/search.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/search.md new file mode 100644 index 000000000..3872f2975 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/search.md @@ -0,0 +1,202 @@ +# Cerca + +Flarum tratta la ricerca e il filtraggio come processi paralleli ma distinti. Quale processo viene utilizzato per gestire una richiesta a [`List` API endpoint](/extend/api.md#api-endpoints) dipende dai parametri della query: + +- Il filtro viene applicato quando il parametro della query `filter[q]` viene omesso. I filtri rappresentano **query strutturate**: per esempio, potresti voler recuperare solo le discussioni in una determinata categoria, o gli utenti che si sono registrati prima di una certa data. Filtrando i risultati dei calcoli basati interamente sui parametri `filter[KEY] = VALORE` query. +- La ricerca viene applicata quando il `filter[q]` query param è incluso. Le ricerche rappresentano **query non strutturate** : l'utente invia una stringa arbitraria e i record di dati che "corrispondono" sono restituiti. For instance, you might want to search discussions based on the content of their posts, or users based on their username. Ricerca dei risultati dei calcoli basata esclusivamente sull'analisi del parametro `filter[q]`: tutti gli altri `filter[KEY] = VALUE` vengono ignorati durante la ricerca. È importante notare che le ricerche non sono completamente strutturate: il set di dati ricercato può essere vincolato dai gambits (che sono molto simili ai filtri, e li vedremo più avanti). + +This distinction is important because searches and filters have very different use cases: filters represent *browsing*: that is, the user is passively looking through some category of content. In contrast, searches represent, well, *searching*: the user is actively looking for content based on some criteria. + +Flarum implements searching and filtering via per-model `Searcher` and `Filterer` classes (discussed in more detail below). Both classes accept a [`Flarum\Query\QueryCriteria`](https://api.docs.flarum.org/php/master/flarum/query/querycriteria) instance (a wrapper around the user and query params), and return a [`Flarum\Query\QueryResults`](https://api.docs.flarum.org/php/master/flarum/query/queryresults) instance (a wrapper around an Eloquent model collection). This common interface means that adding search/filter support to models is quite easy. + +One key advantage of this split is that it allows searching to be implemented via an external service, such as ElasticSearch. For larger communities, this can be significantly more performant and accurate. There isn't a dedicated extender for this yet, so for now, replacing the default Flarum search driver requires overriding the container bindings of `Searcher` classes. This is a highly advanced use case; if you're interested in doing this, please reach out on our [community forums](https://discuss.flarum.org/). + +Remember that the [JSON:API schema](https://jsonapi.org/format) is used for all API requests. + +:::tip Reuse Code + +Often, you might want to use the same class as both a `Filter` and a `Gambit` (both explained below). Your classes can implement both interface; see Flarum core's [`UnreadFilterGambit`](https://github.com/flarum/framework/blob/main/framework/core/src/Discussion/Query/UnreadFilterGambit.php) for an example. + +::: + +:::tip Query Builder vs Eloquent Builder + +`Filter`s, `Gambit`s, filter mutators, and gambit mutators (all explained below) receive a "state" parameter, which wraps + +::: + +## Filtering + +Filtering constrains queries based on `Filters` (highlighted in code to avoid confusion with the process of filtering), which are classes that implement `Flarum\Filter\FilterInterface` and run depending on query parameters. After filtering is complete, a set of callbacks called "filter mutators" run for every filter request. + +When the `filter` method on a `Filterer` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Filter/AbstractFilterer.php#L50-L93)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Filterer` class's `getQuery()` method. +2. We loop through all `filter[KEY] = VALUE` query params. For each of these, any `Filter`s registered to the model whose `getFilterKey()` method matches the query param `KEY` is applied. `Filter`s can be negated by providing the query param as `filter[-KEY] = VALUE`. Whether or not a `Filter` is negated is passed to it as an argument: implementing negation is up to the `Filter`s. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "filter mutators" are applied. These are callbacks that receive the filter state (a wrapper around the query builder and current user) and filter criteria, and perform some arbitrary changes. All "filter mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Filtering for an Existing Model + +Let's say you've added a `country` column to the User model, and would like to filter users by country. We'll need to define a custom `Filter`: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +Note that `FilterState` is a wrapper around the Eloquent builder's underlying Query builder and the current user. + +Also, let's pretend that for some reason, we want to omit any users that have a different country from the current user on ANY filter. We can use a "filter mutator" for this: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +Now, all we need to do is register these via the Filter extender: + +```php + // Other extenders + (new Extend\Filter(UserFilterer::class)) + ->addFilter(CountryFilter::class) + ->addFilterMutator(OnlySameCountryFilterMutator::class), + // Other extenders +``` + +### Add Filtering to a New Model + +To filter a model that doesn't support filtering, you'll need to create a subclass of `Flarum/Filter/AbstractFilterer` for that model. For an example, see core's [UserFilterer](https://github.com/flarum/framework/blob/main/framework/core/src/User/Filter/UserFilterer.php). + +Then, you'll need to use that filterer in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +## Searching + +Searching constrains queries by applying `Gambit`s, which are classes that implement `Flarum\Search\GambitInterface`, based on the `filter[q]` query param. After searching is complete, a set of callbacks called "search mutators" run for every search request. + +When the `search` method on a `Searcher` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Search/AbstractSearcher.php#L55-L79)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Searcher` class's `getQuery()` method. +2. The `filter[q]` param is split by spaces into "tokens". Each token is matched against the model's registered `Gambit`s (each gambit has a `match` method). For any tokens that match a gambit, that gambit is applied, and the token is removed from the query string. Once all regular `Gambit`s have ran, all remaining unmatched tokens are passed to the model's `FullTextGambit`, which implements the actual searching logic. For example if searching discussions, in the `filter[q]` string `'author:1 hello is:hidden' world`, `author:1` and `is:hidden` would get matched by core's Author and Hidden gambits, and `'hello world'` (the remaining tokens) would be passed to the `DiscussionFulltextGambit`. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "search mutators" are applied. These are callbacks that receive the search state (a wrapper around the query builder and current user) and criteria, and perform some arbitrary changes. All "search mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Searching for an Existing Model + +Let's reuse the "country" examples we used above, and see how we'd implement the same things for searching: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +:::warning No Spaces in Gambit Patterns! + +Flarum splits the `filter[q]` string into tokens by splitting it at spaces. This means that your custom gambits can NOT use spaces as part of their pattern. + +::: + +:::tip AbstractRegexGambit + +All a gambit needs to do is implement `Flarum\Search\GambitInterface`, which receives the search state and a token. It should return if this gambit applies for the given token, and if so, make whatever mutations are necessary to the query builder accessible as `$searchState->getQuery()`. + +However, for most gambits, the `AbstractRegexGambit` abstract class (used above) should be used as a base class. This makes it a lot simpler to match and apply gambits. + +::: + +Similarly, the search mutator we need is almost identical to the filter mutator from before: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +We can register these via the `SimpleFlarumSearch` extender (in the future, the `Search` extender will be used for registering custom search drivers): + +```php + // Other extenders + (new Extend\SimpleFlarumSearch(UserSearcher::class)) + ->addGambit(CountryGambit::class) + ->addSearchMutator(OnlySameCountrySearchMutator::class), + // Other extenders +``` + +### Add Searching to a New Model + +To support searching for a model, you'll need to create a subclass of `Flarum/Search/AbstractSearcher` for that model. For an example, see core's [UserSearcher](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/UserSearcher.php). + +Then, you'll need to use that searcher in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +Every searcher **must** have a fulltext gambit (the logic that actually does the searching). Otherwise, it won't be booted by Flarum, and you'll get an error. See core's [FulltextGambit for users](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/Gambit/FulltextGambit.php) for an example. You can set (or override) the full text gambit for a searcher via the `SimpleFlarumSearch` extender's `setFullTextGambit()` method. + +### Search Drivers + +Coming soon! + +## Frontend Tools + +Coming soon! diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md new file mode 100644 index 000000000..7d8590174 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md @@ -0,0 +1,65 @@ +# Provider di servizi + +Come notato in questa documentazione, Flarum utilizza [il contenitore dei servizi Laravel](https://laravel.com/docs/6.x/container) (o IoC container) per l'iniezione di dipendenze. [I provider di servizi](https://laravel.com/docs/6.x/providers) consentono la configurazione e la modifica del backend Flarum a basso livello. Il caso d'uso più comune per i provider di servizi è creare, modificare o sostituire i binding del contenitore. Detto questo, i provider di servizi consentono l'accesso completo per eseguire qualsiasi logica necessaria durante l'avvio dell'applicazione con accesso al contenitore. + +:::caution Solo per utenti avanzati!!! + +A differenza di altri estensori, il livello del provider di servizi NON è basato sul caso d'uso e NON è considerato API pubblica. È soggetto a modifiche in qualsiasi momento, senza preavviso. E dovrebbe essere usato solo se sai cosa stai facendo e gli altri extender non soddisfano il tuo caso d'uso. + +::: + +## Processi di Boot di Flarum + +Per comprendere i provider di servizi, devi prima capire l'ordine in cui Flarum si avvia. Most of this happens in [Flarum\Foundation\InstalledSite](https://github.com/flarum/framework/blob/main/framework/core/src/Foundation/InstalledSite.php) + +1. Il contenitore e l'applicazione vengono inizializzati e vengono registrati i collegamenti essenziali (configurazione, ambiente, logger) +2. Il metodo `register` di tutti i principali provider di servizi viene eseguito. +3. Il metodo `extend`di tutti gli extender utilizzati dalle estensioni sono avviati. +4. Il metodo `extend` di tutti gli extender utilizzati nel file Flarum `extend.php` è avviato. +5. Il metodo `boot` di tutti i provider di servizi principali è avviato. + +## Provider di servizi personalizzato + +Un provider di servizi personalizzato dovrebbe estendersi in `Flarum\Foundation\AbstractServiceProvider`, e può avere metodi `boot` e `register`. Per esempio: + +```php +container->resolving(SomeClass::class, function ($container) { + return new SomeClass($container->make('some.binding')); + }); + } + + public function boot(Container $container) + { + // custom logic here + } +} +``` + +Il metodo `register` verrà eseguito durante il passaggio (3) qui sopra, e il metodo `boot` verrà eseguito durante la fase (5). In entrambi i metodi, il contenitore è disponibile tramite `$this->app`. In the `boot` method, the container (or any other arguments), should be injected via typehinted method arguments. + +Flarum does not currently support Laravel Octane, but some [best practices](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane), like using the `$container` argument inside `bind`, `singleton`, and `resolving` callbacks instead of `$this->container` should be used. See the [Octane documentation](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane) for more information. + +Per registrare effettivamente il tuo provider di servizi personalizzato, puoi utilizzare l'extender `ServiceProvider` in `extend.php`: + +```php +register(CustomServiceProvider::class), + // Other extenders +]; +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/settings.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/settings.md new file mode 100644 index 000000000..a8e15e917 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/settings.md @@ -0,0 +1,90 @@ +# Impostazioni + +Ad un certo punto durante la creazione di un'estensione, potresti voler leggere alcune delle impostazioni del forum o memorizzare determinate impostazioni specifiche per la tua estensione. Per fortuna, Flarum lo rende molto semplice. + +## La repository Impostazioni + +La lettura o la modifica delle impostazioni può essere eseguita utilizzando un'implementazione di `SettingsRepositoryInterface`. Invece, puoi fare affidamento sul contenitore per istanziare la tua classe e inserire le dipendenze corrette. Poichè Flarum utilizza [il contenitore di servizi di Laravel](https://laravel.com/docs/6.x/container) (o IoC container)per l'inserimento di dipendenze, non è necessario preoccuparsi di dove ottenere tale repository o di come istanziarne una. + +```php +settings = $settings; + } +} +``` + +Grande! Perfetto, ora `SettingsRepositoryInterface` è disponibile tramite la classe `$this->settings`. + +### Leggere le impostazioni + +Per leggere le impostazioni, tutto ciò che dobbiamo fare è utilizzare la funzione della repository `get()`: + +`$this->settings->get('forum_title')` + +La funzione `get()` accetta i seguenti argomenti: + +1. Il nome dell'impostazione che stai tentando di leggere. +2. (Facoltativo) Un valore predefinito se non è stato memorizzato alcun valore per tale impostazione. Per impostazione predefinita, questo sarà `null`. + +### Memorizzazione delle impostazioni + +Memorizzare le impostazioni è altrettanto facile, usa la funzione `set()`: + +`$this->settings->set('forum_title', 'Super Awesome Forum')` + +La funzione `set` accetta i seguenti argomenti: + +1. Il nome dell'impostazione che stai tentando di modificare. +2. Il valore che desideri memorizzare per questa impostazione. + +### Altre funzioni + +La funzione `all()` restituisce un array di tutte le impostazioni conosciute. + +La funzione `delete($name)` ti consente di rimuovere un'impostazione con nome. + +## Impostazioni nel frontend + +### Modifica delle impostazioni + +Per ulteriori informazioni sulla gestione delle impostazioni tramite la dashboard dell'amministratore, consultare la [documentazione pertinente](admin.md). +### Accesso alle impostazioni + +Tutte le impostazioni sono disponibili nel frontend `admin` tramite `app.data.settings`. Tuttavia, questo non viene mostrato nel frontend `forum`, poiché chiunque può accedervi e non vorrai perdere tutte le tue impostazioni! (Scherzi a parte, potrebbe essere una violazione dei dati molto problematica). + +Se invece vogliamo utilizzare le impostazioni nel frontend `forum`, dovremo serializzarli e inviarli insieme al payload iniziale dei dati del forum. + +Questo può essere fatto tramite l'extender `Settings`. Per esempio: + +**extend.php** + +```php +use Flarum\Extend; + +return [ + (new Extend\Settings) + ->serializeToForum('myCoolSetting', 'my.cool.setting.key') + ->serializeToForum('myCoolSettingModified', 'my.cool.setting.key', function ($retrievedValue) { + // This third argument is optional, and allows us to pass the retrieved setting through some custom logic. + // In this example, we'll append a string to it. + + return "My Cool Setting: $retrievedValue"; + }), +] +``` + +Ora, l'impostazione `my.cool.setting.key` sarà disponibile nel frontend come `app.forum.attribute("myCoolSetting")`, e il nostro valore modificato sarà accessibile tramite `app.forum.attribute("myCoolSettingModified")`. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md new file mode 100644 index 000000000..288dc9269 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md @@ -0,0 +1 @@ +# Modello Slugging diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/start.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/start.md new file mode 100644 index 000000000..ce22a2d9d --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/start.md @@ -0,0 +1,153 @@ +# Iniziare + +Vuoi costruire un'estensione Flarum? Sei nel posto giusto! Questo documento ti guider� attraverso alcuni concetti essenziali, dopodich� costruirai la tua prima estensione Flarum da zero. + +## Architettura + +Per capire come estendere Flarum, prima dobbiamo capire un po' come � costruito Flarum. + +Tieni presente che Flarum utilizza alcuni linguaggi e strumenti _moderni_. Se hai mai creato solo plugin per WordPress prima, potresti sentirti un po' fuori dal tuo ambiente! Va bene, questo � un ottimo momento per imparare cose nuove e interessanti ed estendere le tue abilit�. Tuttavia, ti consigliamo di acquisire familiarit� con le tecnologie descritte di seguito prima di procedere. + +Flarum � composto da tre strati: + +* Primo, c'� il ** backend **. Questo � scritto in formato [object-oriented PHP](https://laracasts.com/series/object-oriented-bootcamp-in-php), e fa uso di un'ampia gamma di array e componenti [Laravel](https://laravel.com/) e pacchetti tramite [Composer](https://getcomposer.org/). Ti consigliamo anche di familiarizzare con il concetto di [iniezione dipendenze](https://laravel.com/docs/6.x/container), che viene utilizzato in tutto il nostro backend. + +* Secondo, il backend espone una ** API pubblica ** che consente ai client frontend di interfacciarsi con i dati del tuo forum. Questo � costruito secondo il [specifiche JSON:API](https://jsonapi.org/). + +* Ed ultimo, c'� l'interfaccia web predefinita che chiamiamo ** frontend **. Questa � una [applicazione a pagina singola](https://en.wikipedia.org/wiki/Single-page_application) che utilizza le API. � costruito con un semplice framework simile a React chiamato [Mithril.js](https://mithril.js.org). + +Le estensioni dovranno spesso interagire con tutti e tre questi livelli per far accadere le cose. Ad esempio, se si desidera creare un'estensione che aggiunga campi personalizzati ai profili utente, � necessario aggiungere le strutture di database appropriate nel ** backend **, esporre tali dati nell '** API pubblica ** e quindi visualizzare e consentire agli utenti di modificarlo sul ** frontend **. + +Allora ... come estendiamo questi livelli? + +## Extender + +Per estendere Flarum, useremo un concetto chiamato ** extender **. Gli extender sono oggetti * dichiarativi * che descrivono in termini semplici gli obiettivi che stai cercando di raggiungere (come aggiungere un nuovo percorso al tuo forum o eseguire del codice quando � stata creata una nuova discussione). + +Ogni extender � diverso. Tuttavia, saranno sempre in qualche modo simili a questo: + +```php +// Register a JavaScript and a CSS file to be delivered with the forum frontend +(new Extend\Frontend('forum')) + ->js(__DIR__.'/forum-scripts.js') + ->css(__DIR__.'/forum-styles.css') +``` + +Creare prima un'istanza dell'extender, quindi chiamare i metodi su di essa per un'ulteriore configurazione. Tutti questi metodi restituiscono l'extender stesso, in modo da poter ottenere l'intera configurazione semplicemente concatenando le chiamate ai metodi. + +Per mantenere le cose coerenti, usiamo questo concetto di estensori sia nel backend (nel mondo PHP) che nel frontend (mondo JavaScript). _Tutto_ quello che fai nella tua estensione dovrebbe essere fatto tramite extender, perch� sono una ** garanzia ** che ti stiamo dando che una futura versione minore di Flarum non interromper� la tua estensione. + +All of the extenders currently available to you from Flarum's core can be found in the [`Extend` namespace](https://github.com/flarum/framework/blob/main/framework/core/src/Extend) [(PHP API documentation)](https://api.docs.flarum.org/php/master/flarum/extend) Extensions may also offer their [own extenders](extensibility.md#custom-extenders). + +## Ciao Mondo + +Vuoi vedere un extender in azione? Il file `extend.php` nella root della tua installazione di Flarum � il modo pi� semplice per registrare gli extender per il tuo sito. Dovrebbe restituire un array di oggetti extender. Aprilo e aggiungi quanto segue: + +```php +content(function (Document $document) { + $document->head[] = ''; + }) +]; +``` + +Ora visita il tuo forum per un saluto piacevole (anche se estremamente invadente). 👋 + +Per semplici personalizzazioni specifiche del sito come l'aggiunta di un po 'di CSS / JavaScript personalizzato o l'integrazione con il sistema di autenticazione del tuo sito, il file il file `extend.php` � praticamente perfetto. Ma a un certo punto, la tua personalizzazione potrebbe diventare troppo grande. Or maybe you have wanted to build an extension to share with the community from the get-go. � ora di costruire un'estensione! + +## Pacchetto estensione + +[Composer](https://getcomposer.org) � un gestore delle dipendenze per PHP. Consente alle applicazioni di inserire facilmente librerie di codice esterne e rende facile mantenerle aggiornate in modo che la sicurezza e le correzioni di bug vengano propagate rapidamente. + +A quanto pare, ogni estensione Flarum � anche un pacchetto Composer. Ci� significa che l'installazione di Flarum di qualcuno pu� "richiedere" una certa estensione e Composer la inserir� e la manterr� aggiornata. Bello no? + +Durante lo sviluppo, puoi lavorare sulle tue estensioni localmente e configurare un [repository di Composer](https://getcomposer.org/doc/05-repositories.md#path) per installare la tua copia locale. Crea una nuova cartella `packages` nella radice della tua installazione di Flarum, quindi esegui questo comando per dire a Composer che pu� trovare i pacchetti qui: + +```bash +composer config repositories.0 path "packages/*" +``` + +Ora iniziamo a costruire la nostra prima estensione. Crea una nuova cartella all'interno di quella `packages` per la tua estensione, chiamata `hello-world`. Vi inseriremo due file, `extend.php` e `composer.json`. Questi file sono il cuore e l'anima dell'estensione. + +### extend.php + +Il file `extend.php` � proprio come quello nella radice del tuo sito. Restituir� un array di oggetti extender che dicono a Flarum cosa vuoi fare. Per ora, spostati sull'extender `Frontend` fatto prima. + +### composer.json + +Dobbiamo parlare un po' a Composer del nostro pacchetto, e possiamo farlo creando un file `composer.json`: + +```json +{ + "name": "acme/flarum-hello-world", + "description": "Say hello to the world!", + "type": "flarum-extension", + "require": { + "flarum/core": ">=0.1.0-beta.15 <0.1.0-beta.16" + }, + "autoload": { + "psr-4": {"Acme\\HelloWorld\\": "src/"} + }, + "extra": { + "flarum-extension": { + "title": "Hello World", + "icon": { + "name": "fas fa-smile", + "backgroundColor": "#238c59", + "color": "#fff" + } + } + } +} +``` + +* ** nome ** � il nome del pacchetto Composer nel formato `creatore/pacchetto`. + * Dovresti scegliere un nome fornitore che sia univoco, ad esempio il tuo nome utente GitHub. Ai fini di questo tutorial, supporremo che tu stia utilizzando `acme`come nome creatore. + * Dovresti aggiungere il prefisso `package` con `flarum-` per indicare che si tratta di un pacchetto specificamente destinato all'uso con Flarum. + +* **description ** � una breve descrizione composta da una frase che spiega ci� che fa l'estensione. + +* **type** DEVE essere impostato su `flarum-extension`. Ci� garantisce che quando qualcuno "richiede" la tua estensione, verr� identificato come tale. + +* **require** contiene un elenco delle dipendenze della tua estensione. + * Dovrai specificare la versione di Flarum con cui la tua estensione � compatibile qui. + * Questo � anche il posto dove elencare altre librerie Composer di cui il tuo codice ha bisogno per funzionare. + +* **autoload** dice a Composer dove trovare le classi della tua estensione. Il nome qui dovrebbe riflettere il fornitore delle estensioni e il nome del pacchetto in CamelCase. + +* **extra.flarum-extension** contiene alcune informazioni specifiche di Flarum, come il nome visualizzato dell'estensione e come dovrebbe apparire la sua icona. + * **title** � il nome visualizzato della tua estensione. + * **icon** � un oggetto che definisce l'icona della tua estensione. La propriet� ** name ** � un icona [Font Awesome](https://fontawesome.com/icons). Tutte le altre propriet� vengono utilizzate dall'attributo `style` per l'icona della tua estensione. + +Guarda la documentazione [schema di composer.json](https://getcomposer.org/doc/04-schema.md) documentation per informazioni su altre propriet� da aggiungere a `composer.json`. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +Usa [FoF extension generator](https://github.com/FriendsOfFlarum/extension-generator) per creare automaticamente lo scheletro della tua estensione +```bash +$ flarum-cli init +``` + +::: + +### Installare la tua estensione + +L'ultima cosa che dobbiamo fare per essere operativi � installare la tua estensione. Vai alla directory root della tua installazione Flarum ed esegui il seguente comando + +```bash +composer require acme/flarum-hello-world *@dev +``` + +Una volta fatto, vai avanti e avvia la pagina di amministrazione del tuo forum. + +*crank, ching, crunk* + +Oopl�! Ciao a te estensione Hello World! + +Stiamo facendo buoni progressi. Abbiamo imparato come impostare la nostra estensione e utilizzare gli estensori, il che apre molte porte. Continua a leggere per scoprire come estendere il frontend di Flarum. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md new file mode 100644 index 000000000..28e6c4aa7 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md @@ -0,0 +1,86 @@ +# Static Code Analysis + +Static code analysis is the process of analyzing the source code against a set of rules to find bugs, code smells, and security vulnerabilities. This is a great way to improve the quality of your code and to find potential issues before they are deployed to production. An example is validating the typings of a function to ensure that the function is called with the correct arguments. + +Flarum provides a static code analysis package based on [PHPStan](https://phpstan.org/) that can be added to your extension. In this guide, we will show you how to add the package to your extension and how to run the analysis. + +## Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update the infrastructure for phpstan to your code: + +```bash +$ flarum-cli infra phpstan +``` + +::: + +First you need to require the `flarum/phpstan` package in your extension. You can do this by running the following command in the root of our extension: + +```bash +composer require --dev flarum/phpstan:^1.0 +``` + +Next, you need to create a `phpstan.neon` file in the root of your extension. This file contains [the configuration for PHPStan](https://phpstan.org/config-reference). You can copy the following configuration into the file: + +```neon +includes: + - vendor/flarum/phpstan/extension.neon + +parameters: + # The level will be increased in Flarum 2.0 + level: 5 + paths: + - src + - extend.php + excludePaths: + - *.blade.php + checkMissingIterableValueType: false + databaseMigrationsPath: ['migrations'] +``` + +Finally, you need to add the following script to your `composer.json` file: + +```json +{ + "scripts": { + "analyse:phpstan": "phpstan analyse", + "clear-cache:phpstan": "phpstan clear-result-cache" + }, + "scripts-descriptions": { + "analyse:phpstan": "Run static analysis" + } +} +``` + +## Running the analysis + +To run the analysis, you can run the following command in the root of your extension: + +```bash +composer analyse:phpstan +``` + +If you want to clear the cache before running the analysis, you can run the following command: + +```bash +composer clear-cache:phpstan && composer analyse:phpstan +``` + +## GitHub Actions + +You can also run the analysis using GitHub Actions. Checkout the page on [GitHub Actions](github-actions.md) for more information. + +## Tips + +### Extended model attribute types + +PHPStan needs to be able to determine the type of an attribute added to an existing model. To do this you can use the `Extend\Model(...)->cast(...)` method. + +For example, if your extension were to add a `is_cool` attribute to the `User` model, you can use [attribute casting](https://laravel.com/docs/8.x/eloquent-mutators#attribute-casting) to explicitly define the attribute as boolean. The `flarum/phpstan` package will automatically detect this and communicate it to PHPStan. + +```php +(new Extend\Model(User::class)) + ->cast('is_cool', 'bool'), +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/testing.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/testing.md new file mode 100644 index 000000000..7b45a1f70 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/testing.md @@ -0,0 +1,565 @@ +# Test + +Automated testing ensures that your extension performs as you expect it to, helps avoid introducing new bugs or regressions, and saves time on manual testing. Flarum currently provides tooling for automated backend unit and integration tests, and we plan to release support for frontend unit testing and E2E testing in the future. + +## Backend Tests + +The `flarum/testing` library is used by core and some bundled extensions for automated unit and integration tests. It is essentially a collection of utils that allow testing Flarum core and extensions with PHPUnit. + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update backend testing infrastructure to your code: + +```bash +$ flarum-cli infra backendTesting +``` + +::: + +```bash +composer require --dev flarum/testing:^1.0 +``` + +Then, you will need to set up a file structure for tests, and add PHPUnit configuration: + +``` +tests +├── fixtures (put any files needed by your tests here (blade templates, images, etc)) +├── integration +│ ├── setup.php (code below) +│ └── PUT INTEGRATION TESTS HERE (organizing into folder is generally a good idea) +├── unit +│ ├── PUT UNIT TESTS HERE +├── phpunit.integration.xml (code below) +└── phpunit.unit.xml (code below) +``` + +#### phpunit.integration.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for integration tests. You can tweak this as needed, but keep `backupGlobals`, `backupStaticAttributes`, and `processIsolation` unchanged. + +```xml + + + + + + + ./integration + + + +``` + +#### phpunit.unit.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for unit tests. You can tweak this as needed. + +```xml + + + + + + + ./unit + + + + + + +``` + +#### setup.php + +This script will be run to set up a testing database / file structure. + +```php +run(); +``` + +#### composer.json Modifications + +We will also want to add scripts to our `composer.json`, so that we can run our test suite via `composer test`. Add some variant of the following to your `composer.json`: + +```json +"scripts": { + "test": [ + "@test:unit", + "@test:integration" + ], + "test:unit": "phpunit -c tests/phpunit.unit.xml", + "test:integration": "phpunit -c tests/phpunit.integration.xml", + "test:setup": "@php tests/integration/setup.php" +}, +"scripts-descriptions": { + "test": "Runs all tests.", + "test:unit": "Runs all unit tests.", + "test:integration": "Runs all integration tests.", + "test:setup": "Sets up a database for use with integration tests. Execute this only once." +} +``` + +#### GitHub Testing Workflow + +To run tests on every commit and pull request, check out the [GitHub Actions](github-actions.md) page. + +--- + +Now that we have everything in place, we need to set up our testing site for integration tests. For this, we will need a MySQL or MariaDb instance, and a place to store testing files. + +Testing database information is configured via the `DB_HOST` (defaults to `localhost`), `DB_PORT` (defaults to `3306`), `DB_DATABASE` (defaults to `flarum_test`), `DB_USERNAME` (defaults to `root`), `DB_PASSWORD` (defaults to `root`), and `DB_PREFIX` (defaults to `''`) environmental variables. The testing tmp directory path is configured via the `FLARUM_TEST_TMP_DIR_LOCAL` or `FLARUM_TEST_TMP_DIR` environmental variables, with the former taking precedence over the latter. If neither are provided, a `tmp` directory will be created in the `vendor` folder of your extension's local install. + +Now that we've provided the needed information, all we need to do is run `composer test:setup` in our extension's root directory, and we have our testing environment ready to go! + +Since [(almost)](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/tests/integration/api/discussions/ListWithFulltextSearchTest.php#L29-L45) all database operations in integration tests are run in transactions, developers working on multiple extensions will generally find it more convenient to use one shared database and tmp directory for testing all their extensions. To do this, set the database config and `FLARUM_TEST_TMP_DIR` environmental variables in your `.bashrc` or `.bash_profile` to the path you want to use, and run the setup script for any one extension (you'll still want to include the setup file in every repo for CI testing via GitHub Actions). You should then be good to go for any Flarum extension (or core). + +### Using Integration Tests + +Flarum's integration test utils are contained in the `Flarum\Testing\integration\TestCase` class. It: + +- Boots (and makes available) an instance of the Flarum application. +- Allows pre-populating the database, enabling extensions, and adding extenders. +- Runs all database changes in transactions, so your test database retains the default post-installation state. +- Allows sending requests through the middleware stack to test HTTP endpoints. + +Your testcase classes should extend this class. + +#### Test Case Setup + +There are several important utilities available for your test cases: + +- The `setting($key, $value)` method allows you to override settings before the app has booted. This is useful if your boot process has logic depending on settings (e.g. which driver to use for some system). +- Similarly, the `config($key, $value)` method allows you to override config.php values before the app has booted. You can use dot-delimited keys to set deep-nested values in the config array. +- The `extension($extensionId)` method will take Flarum IDs of extensions to enable as arguments. Your extension should always call this with your extension's ID at the start of test cases, unless the goal of the test case in question is to confirm some behavior present without your extension, and compare that to behavior when your extension is enabled. If your extension is dependent on other extensions, make sure they are included in the composer.json `require` field (or `require-dev` for [optional dependencies](extending-extensions.md)), and also list their composer package names when calling `extension()`. Note that you must list them in a valid order. +- The `extend($extender)` method takes instances of extenders as arguments, and is useful for testing extenders introduced by your extension for other extensions to use. +- The `prepareDatabase()` method allow you to pre-populate your database. This could include adding users, discussions, posts, configuring permissions, etc. Its argument is an associative array that maps table names to arrays of [record arrays](https://laravel.com/docs/8.x/queries#insert-statements). + +If your test case needs users beyond the default admin user, you can use the `$this->normalUser()` method of the `Flarum\Testing\integration\RetrievesAuthorizedUsers` trait. + +:::warning + +The `TestCase` class will boot a Flarum instance the first time its `app()` method is called. Any uses of `prepareDatabase`, `extend`, or `extension` after this happens will have no effect. Make sure you have done all the setup you need in your test case before calling `app()`, or `database()`, `server()`, or `send()`, which call `app()` implicitly. If you need to make database modifications after the app has booted, you can use the regular Eloquent save method, or the `Illuminate\Database\ConnectionInterface` instance obtained via calling the `database()` method. + +::: + +Of course, since this is all based on PHPUnit, you can use the `setUp()` methods of your test classes for common setup tasks. + +Per esempio: + +```php +setting('my.custom.setting', true); + + // Let's assume our extension depends on tags. + // Note that tags will need to be in your extension's composer.json's `require-dev`. + // Also, make sure you include the ID of the extension currently being tested, unless you're + // testing the baseline without your extension. + $this->extension('flarum-tags', 'my-cool-extension'); + + // Note that this input isn't validated: make sure you're populating with valid, representative data. + $this->prepareDatabase([ + 'users' => [ + $this->normalUser() // Available for convenience. + ], + 'discussions' => [ + ['id' => 1, 'title' => 'some title', 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 1, 'first_post_id' => 1, 'comment_count' => 1] + ], + 'posts' => [ + ['id' => 1, 'number' => 1, 'discussion_id' => 1, 'created_at' => Carbon::now(), 'user_id' => 1, 'type' => 'comment', 'content' => '

something

'] + ] + ]); + + // Most test cases won't need to test extenders, but if you want to, you can. + $this->extend((new CoolExtensionExtender)->doSomething('hello world')); + } + + /** + * @test + */ + public function some_phpunit_test_case() + { + // ... + } + + // ... +} +``` + +#### Sending Requests + +A common application of automated testing is pinging various HTTP endpoints with various data, authenticated as different users. You can use this to ensure that: + +- Users can't access content they're not supported to access. +- Permission-based create/edit/delete operations perform as expected. +- The type and schema of data returned is correct. +- Some desired side effect is applied when pinging an API. +- The basic API operations needed by your extension aren't erroring, and don't break when you make changes. + +`TestCase` provides several utilities: + +- The `request()` method constructs a `Psr\Http\Message\ServerRequestInterface` implementing object from a path, a method, and some options, which can be used for authentication, attaching cookies, or configuring the JSON request body. See the [method docblock](https://github.com/flarum/testing/blob/main/src/integration/TestCase.php) for more information on available options. +- Once you've created a request instance, you can send it (and get a response object back) via the `send()` method. + +Per esempio: + +```php +send( + $this->request('GET', '/api/users', ['authenticatedAs' => 1]) + ->withQueryParams(['filter' => ['q' => 'john group:1'], 'sort' => 'username']) + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + /** + * @test + */ + public function can_create_user() + { + $response = $this->send( + $this->request( + 'POST', + '/api/users', + [ + 'authenticatedAs' => 1, + 'json' => [ + 'data' => [ + 'attributes' => [ + 'username' => 'test', + 'password' => 'too-obscure', + 'email' => 'test@machine.local' + ] + ] + ] + ] + ) + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + // ... +} +``` + +:::cautela + +If you want to send query parameters in a GET request, you can't include them in the path; you'll need to add them afterwards with the `withQueryParams` method. + +::: + +:::cautela + +This is an extreme edge case, but note that MySQL does not update the fulltext index in transactions, so the standard approach won't work if you're trying to test a modified fulltext query. See [core's approach](https://github.com/flarum/framework/blob/main/framework/core/tests/integration/extenders/SimpleFlarumSearchTest.php) for an example of a workaround. + +::: + +#### Console Tests + +If you want to test custom console commands, you can extend `Flarum\Testing\integration\ConsoleTestCase` (which itself extends the regular `Flarum\Testing\integration\TestCase`). It provides 2 useful methods: + +- `$this->console()` returns an instance of `Symfony\Component\Console\Application` +- `$this->runCommand()` takes an array that will be wrapped in `Symfony\Component\Console\Input\ArrayInput`, and run. See the [Symfony code docblock](https://github.com/symfony/console/blob/5.x/Input/ArrayInput.php#L22) for more information. + +Per esempio: + +```php + 'some:command', // The command name, equivalent of `php flarum some:command` + 'foo' => 'bar', // arguments + '--lorem' => 'ipsum' // options + ]; + + $this->assertEquals('Some Output.', $this->runCommand($input)); + } +} +``` + +### Using Unit Tests + +Unit testing in Flarum uses [PHPUnit](https://phpunit.de/getting-started/phpunit-9.html) and so unit testing in flarum is much like any other PHP application. You can find [general tutorials on testing](https://www.youtube.com/watch?v=9-X_b_fxmRM) if you're also new to php. + +When writing unit tests in Flarum, here are some helpful tips. + +#### Mocking Flarum Services + +Unlike the running app, or even integration tests, there is no app/container/etc to inject service instances into our classes. Now all the useful settings, or helpers your extension use require a _mock_ . We want to limit mocking to just the key services, supporting only the minimum interactions needed to test the contract of our individual functions. + +```php + public function setUp(): void + { + parent::setUp(); + // example - if our setting needs settings, we can mock the settings repository + $settingsRepo = m::mock(SettingsRepositoryInterface::class); + // and then control specific return values for each setting key + $settingsRepo->shouldReceive('get')->with('some-plugin-key')->andReturn('some-value-useful-for-testing'); + // construct your class under test, passing mocked services as needed + $this->serializer = new YourClassUnderTest($settingsRepo); + } +``` + +Some aspects require more mocks. If you're validating authorization interactions for instance you might need to mock your users `User::class` and the request's method that provides them as well! + +``` + $this->actor = m::mock(User::class); + $request = m::mock(Request::class)->makePartial(); + $request->shouldReceive('getAttribute->getActor')->andReturn($this->actor); + $this->actor->shouldReceive('SOME PERMISSION')->andReturn(true/false); +``` + +NOTE: If you find your extension needs _lots and lots_ of mocks, or mocks that feel unrelated, it might be an opportunity to simplify your code, perhaps moving key logic into their own smaller functions (that dont require mocks). + +## Frontend Tests + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update frontend testing infrastructure to your code: + +```bash +$ flarum-cli infra frontendTesting +``` + +::: + +First, you need to install the Jest config dev dependency: + +```bash +$ yarn add --dev @flarum/jest-config +``` + +Then, add the following to your `package.json`: + +```json +{ + "type": "module", + "scripts": { + ..., + "test": "yarn node --experimental-vm-modules $(yarn bin jest)" + } +} +``` + +Rename `webpack.config.js` to `webpack.config.cjs`. This is necessary because Jest doesn't support ESM yet. + +Create a `jest.config.cjs` file in the root of your extension: + +```js +module.exports = require('@flarum/jest-config')(); +``` + +If you are using TypeScript, create tsconfig.test.json with the following content: + +```json +{ + "extends": "./tsconfig.json", + "include": ["tests/**/*"], + "files": ["../../../node_modules/@flarum/jest-config/shims.d.ts"] +} +``` + +Then, you will need to set up a file structure for tests: + +``` +js +├── dist +├── src +├── tests +│ ├── unit +│ │ └── functionTest.test.js +│ ├── integration +│ │ └── componentTest.test.js +├── package.json +├── tsconfig.json +├── tsconfig.test.json +├── jest.config.cjs +└── webpack.config.cjs +``` + +#### GitHub Testing Workflow + +To run tests on every commit and pull request, check out the [GitHub Actions](github-actions.md) page. + +### Using Unit Tests + +Like any other JS project, you can use Jest to write unit tests for your frontend code. Checkout the [Jest docs](https://jestjs.io/docs/using-matchers) for more information on how to write tests. + +Here's a simple example of a unit test fo core's `abbreviateNumber` function: + +```ts +import abbreviateNumber from '../../../../src/common/utils/abbreviateNumber'; + +test('does not change small numbers', () => { + expect(abbreviateNumber(1)).toBe('1'); +}); + +test('abbreviates large numbers', () => { + expect(abbreviateNumber(1000000)).toBe('1M'); + expect(abbreviateNumber(100500)).toBe('100.5K'); +}); + +test('abbreviates large numbers with decimal places', () => { + expect(abbreviateNumber(100500)).toBe('100.5K'); + expect(abbreviateNumber(13234)).toBe('13.2K'); +}); +``` + +### Using Integration Tests + +Integration tests are used to test the components of your frontend code and the interaction between different components. For example, you might test that a page component renders the correct content based on certain parameters. + +Here's a simple example of an integration test for core's `Alert` component: + +```ts +import Alert from '../../../../src/common/components/Alert'; +import m from 'mithril'; +import mq from 'mithril-query'; +import { jest } from '@jest/globals'; + +describe('Alert displays as expected', () => { + it('should display alert messages with an icon', () => { + const alert = mq(m(Alert, { type: 'error' }, 'Shoot!')); + expect(alert).toContainRaw('Shoot!'); + expect(alert).toHaveElement('i.icon'); + }); + + it('should display alert messages with a custom icon when using a title', () => { + const alert = mq(Alert, { type: 'error', icon: 'fas fa-users', title: 'Woops..' }); + expect(alert).toContainRaw('Woops..'); + expect(alert).toHaveElement('i.fas.fa-users'); + }); + + it('should display alert messages with a title', () => { + const alert = mq(m(Alert, { type: 'error', title: 'Error Title' }, 'Shoot!')); + expect(alert).toContainRaw('Shoot!'); + expect(alert).toContainRaw('Error Title'); + expect(alert).toHaveElement('.Alert-title'); + }); + + it('should display alert messages with custom controls', () => { + const alert = mq(Alert, { type: 'error', controls: [m('button', { className: 'Button--test' }, 'Click me!')] }); + expect(alert).toHaveElement('button.Button--test'); + }); +}); + +describe('Alert is dismissible', () => { + it('should show dismiss button', function () { + const alert = mq(m(Alert, { dismissible: true }, 'Shoot!')); + expect(alert).toHaveElement('button.Alert-dismiss'); + }); + + it('should call ondismiss when dismiss button is clicked', function () { + const ondismiss = jest.fn(); + const alert = mq(Alert, { dismissible: true, ondismiss }); + alert.click('.Alert-dismiss'); + expect(ondismiss).toHaveBeenCalled(); + }); + + it('should not be dismissible if not chosen', function () { + const alert = mq(Alert, { type: 'error', dismissible: false }); + expect(alert).not.toHaveElement('button.Alert-dismiss'); + }); +}); +``` + +#### Methods + +These are the custom methods that are available for mithril component tests: +* **`toHaveElement(selector)`** - Checks if the component has an element that matches the given selector. +* **`toContainRaw(content)`** - Checks if the component HTML contains the given content. + +To negate any of these methods, simply prefix them with `not.`. For example, `expect(alert).not.toHaveElement('button.Alert-dismiss');`. For more information, check out the [Jest docs](https://jestjs.io/docs/using-matchers). For example you may need to check how to [mock functions](https://jestjs.io/docs/mock-functions), or how to use `beforeEach` and `afterEach` to set up and tear down tests. + + + +## E2E Tests + +Coming Soon! diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/theme.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/theme.md new file mode 100644 index 000000000..e03310559 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/theme.md @@ -0,0 +1,27 @@ +# Guida rapida + +Flarum "themes" are just extensions. Typically, you'll want to use the `Frontend` extender to register custom [Less](https://lesscss.org/#overview) and JS. Of course, you can use other extenders too: for example, you might want to support settings to allow configuring your theme. + +You can indicate that your extension is a theme by setting the "extra.flarum-extension.category" key to "theme". Per esempio: + +```json +{ + // other fields + "extra": { + "flarum-extension": { + "category": "theme" + } + } + // other fields +} +``` + +All this will do is show your extension in the "theme" section in the admin dashboard extension list. + +## Less Variable Customization + +You can define new Less variables in your extension's Less files. There currently isn't an extender to modify Less variable values in the PHP layer, but this is planned for future releases. + +## Switching Between Themes + +Flarum doesn't currently have a comprehensive system that would support switching between themes. This is planned for future releases. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/translate.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/translate.md new file mode 100644 index 000000000..cc787c0f3 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/translate.md @@ -0,0 +1,40 @@ +# Tradurre Flarum + +### LanguagePack + +Come extender, [`LanguagePack`](https://github.com/flarum/core/blob/master/src/Extend/LanguagePack.php) ti consente di definire che la tua estensione è appunto un language pack. + +Tutto quello che devi fare è istanziarlo, e assicurarti che il tuo language pack sia nella cartella `locale`, e sei a posto! + +Ecco un esempio veloce dal pacchetto [Flarum English](https://github.com/flarum/lang-english/blob/master/extend.php): + +```php +translator->trans('some.translation', ['{username}' => 'Some Username!'])`). +- Non c'è supporto per applicazioni complesse (pluralizzazione nidificata, selezione non basata su numero) +- Come risultato del punto precedente, la genderizzazione è impossibile. E questo è importante per molte lingue. + +### Nuovo sistema + +In v5, Symfony ha abbandonato il suo sistema proprietario `transChoice` a favore dello standard [ICU MessageFormat](https://symfony.com/doc/5.2/translation/message_format.html). Questo risolve praticamente ogni singolo problema sopra menzionato. In questa versione, Flarum passerà completamente a ICU MessageFormat. Cosa significa questo per le estensioni? + +- `transChoice` non dovrebbe essere usato affatto; invece, la variabile passata per la pluralizzazione dovrebbe essere inclusa nei dati. +- Le chiavi per le traduzioni del backend non hanno più bisogno di essere circondate da parentesi graffe. +- Le traduzioni possono ora utilizzare le sintassi [`select` e `plural`](https://symfony.com/doc/5.2/translation/message_format.html). Per `plural`, sono supportati il parametro `offset` e le variabili `#`. +- Queste sintassi `select` e `plural` possono essere annidate. Questa è spesso una cattiva idea anche se (oltre, ad esempio, 2 livelli), in quanto le cose possono diventare inutilmente complesse. + +Non è necessario alcun cambiamento nella denominazione del file di traduzione (Symfony docs dice che è necessario un suffisso `+intl-icu`, ma Flarum interpreterà tutti i file di traduzione come internazionalizzati). + +#### Cambiamenti Futuri + +In futuro ciò servirà da base per ulteriori caratteristiche: + +- I preprocessori consentiranno alle estensioni di modificare gli argomenti passati alle traduzioni. Questo abiliterà la genderizzazione (le estensioni potrebbero estrarre automaticamente un campo di genere da qualsiasi oggetto di tipo "utente" passato). +- We could support internationalized "magic variables" for numbers: currently, `one` is supported, but others (`few`, `many`, etc) currently aren't. +- We could support ordinal formatting in additional to just plural formatting. + +#### Changes Needed in Extensions + +The `transChoice` methods in the frontend and backend have been removed. The `trans` method should always be used for translating, regardless of pluralization. If a translation requires pluralization, make sure you pass in the controlling variable as one of the arguments. + +In the frontend, code that looked like this: + +```js +app.translator.transChoice('some-translation', guestCount, {host: hostName}); +``` + +should be changed to: + +```js +// This uses ES6 key-property shorthand notation. {guestCount: guestCount} is equivalent to {guestCount} +app.translator.trans('some-translation', {host: hostName, guestCount }); +``` + +Similarly, in the backend, + +```php +$translator->transChoice('some-translation', $guestCount, ['{host}' => $hostName]); +``` + +should be changed to: + +```php +$translator->trans('some-translation', ['host' => $hostName, 'guestCount' => $guestCount]); +``` + +Note that in the backend, translation keys were previously wrapped in curly braces. This is no longer needed. + +#### Changes Needed in Translations + +Translations that aren't using pluralization don't need any changes. + +Pluralized translations should be changed as follows: + +`For {count} minute|For {count} minutes` + +to + +`{count, plural, one {For # minute} other {For # minutes}}` + +Note that in this example, `count` is the variable that controls pluralization. If a different variable were used (such as guestCount in the example above), this would look like: + +`{guestCount, plural, one {For # minute} other {For # minutes}}` + +See [our i18n docs](i18n.md) for more information. + +### Permissions Changes + +For a long time, the `viewDiscussions` and `viewUserList` permissions have been confusing. Despite their names: + +- `viewDiscussions` controls viewing both discussions and users. +- `viewUserList` controls searching users, not viewing user profiles. + +To clear this up, in v1.0, these permissions have been renamed to `viewForum` and `searchUsers` respectively. A migration in core will automatically adjust all permissions in the database to use the new naming. However, any extension code using the old name must switch to the new ones immediately to avoid security issues. To help the transfer, a warning will be thrown if the old permissions are referenced. + +We have also slightly improved tag scoping for permissions. Currently, permissions can be applied to tags if: + +- The permission is `viewForum` +- The permission is `startDiscussion` +- The permission starts with `discussion.` + +However, this doesn't work for namespaced permissions (`flarum-acme.discussion.bookmark`), or permissions that don't really have anything to do with discussions, but should still be scoped (e.g. `viewTag`). To counter this, a `tagScoped` attribute can be used on the object passed to [`registerPermission`](admin.md) to explicitly indicate whether the permission should be tag scopable. If this attribute is not provided, the current rules will be used to determine whether the permission should be tag scopable. + +## Frontend + +### Tooltip Changes + +The `flarum/common/components/Tooltip` component has been introduced as a simpler and less framework-dependent way to add tooltips. If your code is creating tooltips directly (e.g. via `$.tooltip()` in `oncreate` methods), you should wrap your components in the `Tooltip` component instead. Per esempio: + +```tsx + + + +``` + +See [the source code](https://github.com/flarum/core/blob/master/js/src/common/components/Tooltip.tsx) for more examples and instructions. + +See [the PR](https://github.com/flarum/core/pull/2843/files) for examples of how to change existing code to use tooltips. + +### PaginatedListState + +The `flarum/common/states/PaginatedListState` state class has been introduced to abstract away most of the logic of `DiscussionListState` and `NotificationListState`. It provides support for loading and displaying paginated lists of JSON:API resources (usually models). In future releases, we will also provide an `PaginatedList` (or `InfiniteScroll`) component that can be used as a base class for these paginated lists. + +Please see [the source code](https://github.com/flarum/core/blob/master/js/src/common/states/PaginatedListState.ts) for a list of methods. + +Note that `flarum/forum/states/DiscussionListState`'s `empty` and `hasDiscussions` methods have been removed, and replaced with `isEmpty` and `hasItems` respectively. Questo è un cambiamento decisivo. + +### New Loading Spinner + +The old `spin.js` based loading indicator has been replaced with a CSS-based solution. For the most part, no changes should be needed in extensions, but in some cases, you might need to update your spinner. This change also makes it easier to customize the spinner. + +See [this discussion](https://discuss.flarum.org/d/26994-beta16-using-the-new-loading-spinner) for more information. + +### classList util + +Ever wrote messy code trying to put together a list of classes for some component? Well, no longer! The [clsx library](https://www.npmjs.com/package/clsx) is now available as the `flarum/common/utils/classList` util. + +### User List + +An extensible user list has been added to the admin dashboard. In future releases, we hope to extract a generic model table component that can be used to list any model in the admin dashboard. + +See [the source code](https://github.com/flarum/core/blob/master/js/src/admin/components/UserListPage.tsx#L41) for a list of methods to extend, and examples of how columns should look like (can be added by extending the `columns` method and adding items to the [ItemList](frontend.md)). + +### Varie + +- Components should now call `super` for ALL Mithril lifecycle methods they define. Before, this was only needed for `oninit`, `onbeforeupdate`, and `oncreate`. Now, it is also needed in `onupdate`, `onbeforeremove`, and `onremove`. See [this GitHub issue](https://github.com/flarum/core/issues/2446) for information on why this change was made. +- The `flarum/common/utils/insertText` and `flarum/common/utils/styleSelectedText` utils have been moved to core from `flarum/markdown`. See `flarum/markdown` for an example of usage. +- The `extend` and `override` utils can now modify several methods at once by passing in an array of method names instead of a single method name string as the second argument. This is useful for extending the `oncreate` and `onupdate` methods at once. +- The `EditUserModal` component is no longer available through the `flarum/forum` namespace, it has been moved to `flarum/common`. Imports should be adjusted. +- The `Model` and `Route` JS extenders have been removed for now. There aren't currently used in any extensions that we know of. We will be reintroducing JS extenders during v1.x releases. +- The `Search` component can now be used with the `SearchState` state class. Previously, `SearchState` was missing the `getInitialSearch` method expected by the `Search` component. + +## Backend + +### Filesystem Extenders + +In this release, we refactored our use of the filesystem to more consistently use [Laravel's filesystem API](https://laravel.com/docs/8.x/filesystem). Extensions can now declare new disks, more easily use core's `flarum-assets` and `flarum-avatars` disks, and create their own storage drivers, enabling CDN and cloud storage support. + +### Compat and Closure Extenders + +In early Flarum versions, the `extend.php` file allowed arbitrary functions that allowed execution of arbitrary code one extension boot. Per esempio: + +```php +return [ + // other extenders + function (Dispatcher $events) { + $events->subscribe(Listener\FilterDiscussionListByTags::class); + $events->subscribe(Listener\FilterPostsQueryByTag::class); + $events->subscribe(Listener\UpdateTagMetadata::class); + } +]; +``` + +This approach was difficult to maintain and provide a well-tested public API for, frequently resolved classes early (breaking all sorts of things), and was not very descriptive. With the extender API completed in beta 16, this approach is no longer necessary. Support for these closures has been removed in this stable version. + +One type of functionality for which the extender replacement isn't obvious is container bindings ([e.g. flarum/pusher](https://github.com/flarum/pusher/blob/v0.1.0-beta.14/extend.php#L33-L49)). This can be done with via the service provider extender (e.g. [a newer version of flarum/pusher](https://github.com/flarum/pusher/blob/master/extend.php#L40-L41)). + +If you are unsure about which extenders should be used to replace your use of callbacks in `extend.php`, or are not sure that such an extender exists, please comment so below or reach out! We're in the final stages of finishing up the extender API, so now is the time to comment. + +### Scheduled Commands + +The [fof/console](https://github.com/FriendsOfFlarum/console) library has been a popular way to schedule commands (e.g. for publishing scheduled posts, running DB-heavy operations, etc) for several release. In Flarum 1.0, this functionality has been brought into core's `Console` extender. See our [console extension documentation](console.md) for more information on how to create schedule commands, and our [console user documentation](../console.md) for more information on how to run scheduled commands. + +### Eager Loading Extender + +As part of solving [N+1 Query issues](https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/) in some [Flarum API endpoints](https://github.com/flarum/core/issues/2637), we have introduced a `load` method on the `ApiController` extender that allows you to indicate relations that should be eager loaded. + +This should be done if you know a relation will always be included, or will always be referenced by controller / permission logic. For example, we will always need the tags of a discussion to check what permissions a user has on that discussion, so we should eager load the discussion's `tags` relationship. Per esempio: + +```php +return [ + // other extenders + (new Extend\ApiController(FlarumController\ListDiscussionsController::class)) + ->addInclude(['tags', 'tags.state', 'tags.parent']) + ->load('tags'), +]; +``` + +### RequestUtil + +The `Flarum\Http\RequestUtil`'s `getActor` and `withActor` should be used for getting/setting the actor (user) on requests. `$request->getAttribute('actor')` and `$request->withAttribute('actor')` are deprecated, and will be removed in v2.0. + +### Varie + +- The `Formatter` extender now has an `unparse` method that allows modifying XML before unparsing content. +- All route names must now be unique. In beta 16, uniqueness was enforced per-method; now, it is mandatory for all routes. +- API requests sent through `Flarum\Api\Client` now run through middleware, including `ThrottleApi`. This means that it is now possible to throttle login/registration calls. +- In beta 16, registering custom [searchers](search.md) was broken. It has been fixed in stable. +- The `post_likes` table in the [flarum/likes](https://github.com/flarum/likes) extension now logs the timestamp when likes were created. This isn't used in the extension, but could be used in other extensions for analytics. +- The `help` attribute of [admin settings](admin.md) no longer disappears on click. +- The `generate:migration` console command has been removed. The [Flarum CLI](https://discuss.flarum.org/d/26525-rfc-flarum-cli-alpha) should be used instead. +- The `GambitManager` util class is now considered internal API, and should not be used directly by extensions. +- The `session` attribute is no longer available on the `User` class. This caused issues with queue drivers, and was not conceptually correct (a user can have multiple sessions). The current session is still available via the `$request` instance. +- The `app`, `base_path`, `public_path`, `storage_path`, and `event` global helpers have been restored, but deprecated perpetually. These exist in case Laravel packages need them; they **should not** be used directly by Flarum extension code. The `flarum/laravel-helpers` package has been abandoned. +- The following deprecated features from beta 16 have been removed: + - The `TextEditor`, `TextEditorButton`, and `SuperTextarea` components are no longer exported through the `flarum/forum` namespace, but through `flarum/common` (with the exception of `SuperTextarea`, which has been replaced with `flarum/common/utils/BasicEditorDriver`). + - Support for `Symfony\Component\Translation\TranslatorInterface` has been removed, `Symfony\Contracts\Translation\TranslatorInterface` should be used instead. + - All backwards compatibility layers for the [beta 16 access token refactors](update-b16.md#access-token-and-authentication-changes) have been removed + - The `GetModelIsPrivate` event has been removed. The `ModelPrivate` extender should be used instead. + - The `Searching` (for both `User` and `Discussion` models), `ConfigureAbstractGambits`, `ConfigureDiscussionGambits`, and `ConfigureUserGambits` events have been removed. The `SimpleFlarumSearch` extender should be used instead. + - The `ConfigurePostsQuery` event has been removed. The `Filter` extender should be used instead. + - The `ApiSerializer` extender's `mutate` method has been removed. The same class's `attributes` method should be used instead. + - The `SearchCriteria` and `SearchResults` util classes have been removed. `Flarum\Query\QueryCriteria` and `Flarum\Query\QueryResults` should be used instead. + - The `pattern` property of `AbstractRegexGambit` has been removed; the `getGambitPattern` method is now a required abstract method. + - The `AbstractSearch` util class has been removed. `Flarum\Search\SearchState` and `Flarum\Filter\FilterState` should be used instead. + - The `CheckingPassword` event has been removed, the `Auth` extender should be used instead. + +## Tags Extension Changes + +As mentioned above, [tag scopable permissions](#permissions-changes) can now be explicitly declared. + +We've also made several big refactors to significantly improve tags performance. + +Firstly, the [Tag](https://github.com/flarum/tags/blob/d093ca777ba81f826157522c96680717d3a90e24/src/Tag.php#L38-L38) model's static `getIdsWhereCan` and `getIdsWhereCannot` methods have been removed. These methods scaled horribly on forums with many tags, sometimes adding several seconds to response time. + +These methods have been replaced with a `whereHasPermission` [Eloquent dynamic scope](https://laravel.com/docs/8.x/eloquent#dynamic-scopes) that returns a query. Per esempio: + +`Tag::whereHasPermission($actor, 'viewDiscussions)`. + +That query can then be used in other DB queries, or further constricted to retrieve individual tags. + +Secondly, we no longer load in all tags as part of the initial payload. The initial payload contains all top-level primary tags, and the top 3 secondary tags. Other tags are loaded in as needed. Future releases will paginate secondary tags. This should enable forums to have thousands of secondary tags without significant performance impacts. These changes mean that extensions should not assume that all tags are available in the model store. + +## Testing Library Changes + +- Bundled extensions will not be automatically enabled; all enabled extensions must be specified in that test case. +- `setting` and `config` methods have been added that allow configuring settings and config.php values before the tested application boots. See [the testing docs](testing.md) for more information. +- The `php flarum test:setup` command will now drop the existing test DB tables before creating the database. This means that you can run `php flarum test:setup` to ensure a clean database without needing to go into the database and drop tables manually. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md new file mode 100644 index 000000000..ed17364ed --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md @@ -0,0 +1,139 @@ +# Updating For 1.x + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## 1.7 + +### Frontend + +- Frontend extenders similar to the backend have been added, we highly recommend using them instead of the old method (https://docs.flarum.org/extend/models#adding-new-models-1), (https://docs.flarum.org/extend/routes#frontend-routes). +- There is a new tag selection component (https://github.com/flarum/framework/blob/360a2ba1d886df3fc6d326be932c5431ee9df8cf/extensions/tags/js/src/common/components/TagSelectionModal.tsx). + +### Backend + +- Support for php 8.2, deprecations are still thrown by some packages, the testing workflow has been updated to ignore deprecations on 8.2 +- The `/api` endpoint now contains the actor as an included relationship. +- The `Model::dateAttribute($attribute)` extender is deprecated, use `Model::cast($attribute, 'datetime')` instead. + +### Tooling + +- New `phpstan` package to run static code analysis on your extensions for code safety (https://docs.flarum.org/extend/static-code-analysis). +- New `jest-config` package to run frontend unit and component tests (https://docs.flarum.org/extend/testing). + +## 1.6 Changes + +### Backend + +- Added customizable session drivers through the `Session` extender. + +## 1.5 Changes + +### Frontend + +- More portions of the frontend are now written in TypeScript, providing a better extension development experience. +- Modals can be used in stacks, allowing for multiple modals to be open at once. This is useful for modals that open other modals: `app.modal.show(ModalComponent, { attrs }, true)`. + +### Backend + +- There is a new `createTableIfNotExists` migration helper, which can be used to create tables only if they don't already exist. + +## 1.4 Changes + +No developer-facing changes were made in Flarum v1.4. + +## 1.3 Changes + +Flarum v1.3 included mostly QoL improvements. Below are listed note worthy changes for extension developers: + +### Frontend + +- More portions of the frontend are now written in TypeScript, providing a better extension development experience. +- Frontend errors will no longer cause the forum to crash into a NoJs page. The extension will fail to execute its frontend code (initializer) and display an error to the admin through an alert, and to all users through the console. The frontend will continue to execute without the extension's frontend changes. +- The markdown toolbar can now be used on the admin side. + +### Backend + +- Calculation of the `number` attribute on `posts` has changed and no longer relies on the discussion model's `post_number_index` attribute which is now deprecated and will be removed in 2.0 +- Extension event listeners are now added after core even listeners, this should generally cause no changes in behavior. + +### Tooling + +- The backend tests workflow now automatically fails tests if there are any PHP warnings and notices. + +## 1.2 Changes + +Flarum v1.2 included quite a few bugfixes, internal refactors, and new features. The following recaps the most important changes for extension developers: + +### Frontend + +- Flarum core now passes TypeScript type checking (on the portion written in TypeScript). Additionally, major portions of the frontend (models, the application instance, and others) are now written in TypeScript. These changes should make it much easier and more fruitful to write extensions in TypeScript. +- Instead of directly using Less variables in CSS code, core now uses CSS variables. For the most part, we've just created CSS variables and set their values to the Less variables. This should make theming and customizing CSS a lot easier. https://github.com/flarum/core/pull/3146. +- Dropdowns can now be lazy-drawn to improve performance. You can do this by setting the lazy draw attr to "true". https://github.com/flarum/core/pull/2925. +- [Textarea-type settings](https://github.com/flarum/core/pull/3141) are now supported through the `app.extensionData.registerSetting` util. +- You can now use Webpack 5 to bundle your extension's code. This will offer minor bundle size improvements. +- A new `flarum/common/components/ColorPreviewInput` component [has been added](https://github.com/flarum/core/pull/3140). It can be used directly, or through the `color-preview` type when registered via `app.extensionData.registerSetting`. +- Extensions can now [modify the minimum search length](https://github.com/flarum/core/pull/3130) of the `Search` component. +- The following components are now extensible: + - The "colors" part of the Appearance page in the admin dashboard: https://github.com/flarum/core/pull/3186 + - The `StatusWidget` dropdown in the admin dashboard: https://github.com/flarum/core/pull/3189 + - `primaryControls` in the notification list: https://github.com/flarum/core/pull/3204 +- Extensions now have finer control over positioning when adding elements to the DiscussionPage sidebar items: https://github.com/flarum/core/pull/3165 +- + +### Backend + +- An [extender for settings defaults](https://github.com/flarum/core/pull/3127) has been added. This should be used instead of the `addSettings` migration helper, which has been deprecated. +- You can now [generate Less variables from setting values](https://github.com/flarum/core/pull/3011) via the `Settings` extender. +- Extensions can now [override/supplement blade template namespaces](https://github.com/flarum/core/pull/3167) through the `View` extender, meaning custom blade templates can be used instead of the default ones added by core or extensions. +- You can now define [custom Less functions through PHP](https://github.com/flarum/core/pull/3190), allowing you to use some backend logic in your Less theming. +- Extensions can now create [custom page title drivers](https://github.com/flarum/core/pull/3109/files) for titles in server-returned HTML. +- Custom logic can now be used when [deciding which relations to eager-load](https://github.com/flarum/core/pull/3116). +- Events [are now dispatched](https://github.com/flarum/core/pull/3203) for the `Notification\Read` and `Notification\ReadAll` events. +- An `ImageManager` instance is now [bound into the container](https://github.com/flarum/core/pull/3195), and can be configured to use either the `gd` or `imagick` backing drivers via the `"intervention.driver"` key in `config.php`. +- User IP addresses are now passed to the [API Client](https://github.com/flarum/core/pull/3124). +- A custom revision versioner implentation [can be set via container bindings](https://github.com/flarum/core/pull/3183) to customize how asset versions are named. +- A SlugManager instance [is now available](https://github.com/flarum/core/pull/3194) in blade templates via the `slugManager` variable. + +### Misc + +- Translations now support the `zero`, `one`, `two`, `few`, and `many` localized plural rules for `plural` ICU MessageFormat translations. This was done through the [`Intl.PluralRules` helper](https://github.com/flarum/core/issues/3072). +- Translations are now used for page titles, so that the format can be customized via language packs or [Linguist](https://discuss.flarum.org/d/7026-linguist-customize-translations-with-ease): https://github.com/flarum/core/pull/3077, https://github.com/flarum/core/pull/3228 +- API endpoints for retrieving single groups, as well as support for filtering groups on the plural get endpoint, [have been added](https://github.com/flarum/core/pull/3084). + + +### Tooling + + +- The `flarum-cli infra` command can now be used to update or enable various infrastructure features. You can now add the following to your extension in just one command: + - TypeScript + - Prettier for JS/TS formatting + - Backend testing with PHPUnit + - Code formatting with StyleCI + - EditorConfig support + - GitHub actions for automating testing, linting, type checking, and building. +- You can also exclude any files from these updates by adding their relative path to the "extra.flarum-cli" key's array in your extension's `composer.json` file. For example, if you wanted to exclude your tsconfig file from any updates by the infra system, the "extra.flarum-cli" key's value should be `["js/tsconfig.json"]`. +- The `flarum-cli audit infra` can be used to check that all infra modules your extension uses are up to date. The `--fix` flag can be used to automatically fix any issues, which has essentially the same effect as running `flarum-cli infra` for each outdated module. +- All `flarum-cli` commands can now be run with a `--no-interaction` flag to prevent prompts. Defaults will be used when possible, and errors will be thrown if a prompt is needed and there is no default. +- Frontend GH actions now support type-checking, as well as type coverage reports. + +## 1.1 Changes + +Flarum version 1.1 mostly focuses on bugfixes and quality-of-life improvements following our stable release earlier this year. These are mainly user-facing and internal infrastructure changes, so extensions are not significantly affected. + +### Frontend + +- Flarum now has an organization-wide prettier config package under [`@flarum/prettier-config`](https://github.com/flarum/prettier-config). +- Most custom (setting or data based) coloring in core is now done via [CSS custom properties](https://github.com/flarum/core/pull/3001). +- Typehinting for Flarum's globals are now [supported in extensions](https://github.com/flarum/core/pull/2992). +- You can now pass extra attrs to the `Select` component, and they will be [passed through to the DOM](https://github.com/flarum/core/pull/2959). +- The `DiscussionPage` component is now organized [as an item list](https://github.com/flarum/core/pull/3004), so it's easier for extensions to change its content. +- Extensions [can now edit](https://github.com/flarum/core/pull/2935) the `page` parameter of `PaginatedListState`. + +### Backend + +- Flarum now comes with a [Preload extender](https://github.com/flarum/core/pull/3057) for preloading any custom frontend assets. +- A new [Theme](https://github.com/flarum/core/pull/3008) extender now allows overriding Less files and internal imports. This allows themes to more easily completely replace Less modules. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md new file mode 100644 index 000000000..aaa98a2a5 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md @@ -0,0 +1,53 @@ +# Updating For Beta 10 + +Beta 10 further solidifies the core architecture, offering new extenders as a stable, use-case-driven API for extending Flarum's core. A few small changes may necessitate updates to your extensions to make them compatible with Beta 10. These are detailed below. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Breaking Changes + +- The `Flarum\Event\GetDisplayName` class has been moved to `Flarum\User\Event\GetDisplayName`. +- The `Flarum\Http\Exception\ForbiddenException` has been removed. Use `Flarum\User\Exception\PermissionDeniedException` instead. +- The `assertGuest()` method of the `Flarum\User\AssertPermissionTrait` has been removed without replacement. +- Old error handling middleware and exception handler classes were removed (see "New Features" for more details): + - `Flarum\Api\Middleware\HandleErrors` + - `Flarum\Http\Middleware\HandleErrorsWithView` + - `Flarum\Http\Middleware\HandleErrorsWithWhoops` + - `Flarum\Api\ErrorHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + - `Flarum\Api\ExceptionHandler\FloodingExceptionHandler` + - `Flarum\Api\ExceptionHandler\IlluminateValidationExceptionHandler` + - `Flarum\Api\ExceptionHandler\InvalidAccessTokenExceptionHandler` + - `Flarum\Api\ExceptionHandler\InvalidConfirmationTokenExceptionHandler` + - `Flarum\Api\ExceptionHandler\MethodNotAllowedExceptionHandler` + - `Flarum\Api\ExceptionHandler\ModelNotFoundExceptionHandler` + - `Flarum\Api\ExceptionHandler\PermissionDeniedExceptionHandler` + - `Flarum\Api\ExceptionHandler\RouteNotFoundExceptionHandler` + - `Flarum\Api\ExceptionHandler\TokenMismatchExceptionHandler` + - `Flarum\Api\ExceptionHandler\ValidationExceptionHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + +## Recommendations + +- We tweaked the [recommended flarum/core version constraints for extensions](start.md#composer-json). We now recommend you mark your extension as compatible with the current and the upcoming beta release. (For beta.10, that would be any beta.10.x and beta.11.x version.) The core team will strive to make this work well by deprecating features before removing them. More details on this change in [this pull request](https://github.com/flarum/docs/pull/75). + +## New Features + +- New, extensible **error handling** stack in the `Flarum\Foundation\ErrorHandling` namespace: The `Registry` maps exceptions to "types" and HTTP status codes, `HttpFormatter` instances turn them into HTTP responses. Finally, `Reporter` instances are notified about unknown exceptions. + - You can build custom exception classes that will abort the current request (or console command). If they have semantic meaning to your application, they should implement the `Flarum\Foundation\KnownError` interface, which exposes a "type" that is used to render pretty error pages or dedicated error messages. + - More consistent use of HTTP 401 and 403 status codes. HTTP 401 should be used when logging in (i.e. authenticating) could make a difference; HTTP 403 is reserved for requests that fail because the already authenticated user is lacking permissions to do something. + - The `assertRegistered()` and `assertPermission()` methods of the `Flarum\User\AssertPermissionTrait` trait have been changed to match above semantics. See [this pull request](https://github.com/flarum/core/pull/1854) for more details. + - Error views are now determined based on error "type", not on status code (see [bdac88b](https://github.com/flarum/core/commit/bdac88b5733643b9c5dabae9e09a64d9f6e41d58)) +- **Queue support**: This release incorporates Laravel's illuminate/queue package, which allows offloading long-running tasks (such as email sending or regular cleanup jobs) onto a dedicated worker process. These changes are mostly under the hood, the next release(s) will start using the queue system for sending emails. By default, Flarum will use the "sync" queue driver, which executes queued tasks immediately. This is far from ideal and mostly guarantees a hassle-free setups. Production-grade Flarum installs are expected to upgrade to a more full-featured queue adapter. +- The `Flarum\Extend\LanguagePack` now accepts an optional path in its constructor. That way, language packs can store their locales in a different directory if they want to. +- The `formatContent()` method of `Flarum\Post\CommentPost` can now be called without an HTTP request instance, e.g. when rendering a post in an email template. + +## Deprecations + +- **Reminder**: In previous versions of Flarum, an extensions' main file was named `bootstrap.php`. This name will no longer be supported in the stable 0.1 release. Make sure your extension uses the name `extend.php`. +- Laravel's global string and array helpers (e.g. `str_contains()` and `array_only()`) are deprecated in favor of their class based alternatives (`Illuminate\Support\Str::contains()` and `Illuminate\Support\Arr::only()`). See the [announcement](https://laravel-news.com/laravel-5-8-deprecates-string-and-array-helpers) and [pull request](https://github.com/laravel/framework/pull/26898) for more information. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md new file mode 100644 index 000000000..ce6b1aca2 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md @@ -0,0 +1,34 @@ +# Updating For Beta 12 + +Beta 12 packs several new features for extension developers, but also continues our cleanup efforts which results in a few changes, so please read this guide carefully to find out whether your extensions are affected. We invested extra effort to introduce new functionality in a backward-compatible manner or first deprecate functionality before it will be removed in the next release, in line with our [versioning recommendations](start.md#composer-json). + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Deprecations / Upcoming breaking changes + +- **Reminder**: In previous versions of Flarum, an extensions' main file was named `bootstrap.php`. This name will no longer be supported in the stable 0.1 release. Make sure your extension uses the name `extend.php`. +- PHP 7.1 support will be dropped in beta.13. +- Using library classes from the `Zend` namespace is now deprecated and will be removed in beta.13. Use the `Laminas` namespace instead. See [PR #1963](https://github.com/flarum/core/pull/1963). +- The `Flarum\Util\Str::slug()` method has been deprecated. Use `Illuminate\Support\Str::slug()` instead. +- The `Flarum\Event\ConfigureMiddleware` has been deprecated. We finally have a [proper replacement](middleware.md) - see "New Features" below. Therefore, it will be removed in beta.13. +- If you implement the `Flarum\Mail\DriverInterface`: + - Returning a plain array of field names from the `availableSettings()` method is deprecated, but still supported. It must now return an array of field names mapping to their type. See [the inline documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L25-L32) for more details. + - Implement the `validate()` method that will be required in beta.13. See [its documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L34-L48). + - Implement the `canSend()` method that will be required in beta.13. See [its documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L50-L54). + +## New Features + +- New **PHP extenders**: + - `Flarum\Extend\Middleware` offers methods for adding, removing or replacing middleware in our three middleware stacks (api, forum, admin). We also added [documentation](middleware.md) for this feature. + - `Flarum\Extend\ErrorHandling` lets you configure status codes and other aspects of our error handling stack depending on error types or exception classes. +- **JavaScript**: + - The `flarum/components/Select` component now supports a `disabled` prop. See [PR #1978](https://github.com/flarum/core/pull/1978). + +## Other changes / Recommendations + +- The `TextFormatter` library has been updated to (at least) version 2.3.6. If you are using it (likely through our own `Flarum\Formatter\Formatter` class), we recommend scanning [the library's changelog](https://github.com/s9e/TextFormatter/blob/2.3.6/CHANGELOG.md). +- The JS `slug()` helper from the `flarum/utils/string` module should only be used to *suggest* slugs to users, not enforce them. It does not employ any sophisticated transliteration logic like its PHP counterpart. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md new file mode 100644 index 000000000..1b19a9714 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md @@ -0,0 +1,40 @@ +# Updating For Beta 13 + +Beta 13 ships with several new extenders to simplify building and maintaining extensions. We do our best to create backward compatibility changes. We recommend changing to new Extenders as soon as they are available. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Breaking Changes + +- Dropped support for PHP 7.1. +- Classes from the `Zend` namespace are now removed. Use the `Laminas` namespace instead. See [PR #1963](https://github.com/flarum/core/pull/1963). +- The `Flarum\Util\Str::slug()` method has been removed including the class. Use `Illuminate\Support\Str::slug()` instead. +- The `Flarum\Event\ConfigureMiddleware` has been removed. Use the [proper replacement](middleware.md). +- Several events used in Event Listeners have been removed, use their [replacement extender](start.md#extenders) instead. +- The LanguagePack extender only loads keys from extensions that are enabled. The translations loaded are based on the yaml files matching the [i18n namespace](i18n.md#appendix-a-standard-key-format). +- All notifications are now sent through the queue; without a queue driver they will run as usual. +- The implementation of avatar upload changed, we're [no longer storing files temporarily on disk](https://github.com/flarum/core/pull/2117). +- The SES mail driver [has been removed](https://github.com/flarum/core/pull/2011). +- Mail driver backward compatibility from beta 12 has been removed, use the new Mail extender or implement the [modified interface](https://github.com/flarum/core/blob/master/src/Mail/DriverInterface.php). + +## Recommendations + +- Beta 14 will ship with a rewrite in the frontend (javascript). If you're building for that release, make sure to follow our [progress](https://github.com/flarum/core/pull/2126). + +## New Features + +- A ton of new extenders: + - [Middleware extender](https://github.com/flarum/core/pull/2017) + - [Console extender](https://github.com/flarum/core/pull/2057) + - [CSRF extender](https://github.com/flarum/core/pull/2095) + - [Event extender](https://github.com/flarum/core/pull/2097) + - [Mail extender](https://github.com/flarum/core/pull/2012) + - [Model extender](https://github.com/flarum/core/pull/2100) + +## Deprecations + +- Several events [have been marked deprecated](https://github.com/flarum/core/commit/4efdd2a4f2458c8703aae654f95c6958e3f7b60b) to be removed in beta 14. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md new file mode 100644 index 000000000..41a005884 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md @@ -0,0 +1,757 @@ +# Updating For Beta 14 + +This release brings a large chunk of breaking changes - hopefully the last chunk of this size before our stable release. In order to prepare the codebase for the upcoming stable release, we decided it was time to modernize / upgrade / exchange some of the underlying JavaScript libraries that are used in the frontend. Due to the nature and size of these upgrades, we have to pass on some of the breaking changes to you, our extension developers. + +On the bright side, this overdue upgrade brings us closer to the conventions of best practices of [Mithril.js](https://mithril.js.org/), the mini-framework used for Flarum's UI. Mithril's 2.0 release sports a more consistent component interface, which should be a solid foundation for years to come. Where possible, we replicated old APIs, to ease the upgrade and give you time to do the full transition. Quite a few breaking changes remain, though - read more below. + +:::tip + +If you need help with the upgrade, our friendly community will gladly help you out either [on the forum](https://discuss.flarum.org/t/extensibility) or [in chat](https://flarum.org/chat/). + +::: + +To ease the process, we've clearly separated the changes to the [frontend (JS)](#frontend-javascript) from those in the [backend (PHP)](#backend-php) below. If your extension does not change the UI, consider yourself lucky. :-) + +A [summary of the frontend changes](#required-frontend-changes-recap) is available towards the end of this guide. + +## Frontend (JavaScript) + +### Mithril 2.0: Concepts + +Most breaking changes required by beta 14 are prompted by changes in Mithril 2. [Mithril's upgrade guide](https://mithril.js.org/migration-v02x.html) is an extremely useful resource, and should be consulted for more detailed information. A few key changes are explained below: + +#### props -> attrs; initProps -> initAttrs + +Props passed into component are now referred to as `attrs`, and can be accessed via `this.attrs` where you would prior use `this.props`. This was done to be closer to Mithril's preferred terminology. We have provided a temporary backwards compatibility layer for `this.props`, but recommend using `this.attrs`. + +Accordingly, `initProps` has been replaced with `initAttrs`, with a similar BC layer. + +#### m.prop -> `flarum/utils/Stream` + +Mithril streams, which were available via `m.prop` in Mithril 0.2, are now available via `flarum/utils/Stream`. `m.prop` will still work for now due to a temporary BC layer. + +#### m.withAttr -> withAttr + +The `m.withAttr` util has been removed from Mithril. We have provided `flarum/utils/withAttr`, which does the same thing. A temporary BC layer has been added for `m.withAttr`. + +#### Lifecycle Hooks + +In mithril 0.2, we had 2 "lifecycle hooks": + +`init`, an unofficial hook which ran when the component instance was initialized. + +`config`, which ran when components were created, and on every redraw. + + +Mithril 2 has the following hooks; each of which take `vnode` as an argument: + +- `oninit` +- `oncreate` +- `onbeforeupdate` +- `onupdate` +- `onbeforeremove` +- `onremove` + +Please note that if your component is extending Flarum's helper `Component` class, you must call `super.METHOD(vnode)` if using `oninit`, `oncreate`, and `onbeforeupdate`. + +More information about what each of these do can be found [in Mithril's documentation](https://mithril.js.org/lifecycle-methods.html). + +A trivial example of how the old methods map to the new is: + +```js +class OldMithrilComponent extends Component { + init() { + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + config(element, isInitialized) { + console.log('Code to run on every redraw AND when the element is first attached'); + + if (isInitialized) return; + + console.log('Code to execute only once when components are first created and attached to the DOM'); + + context.onunload = () => { + console.log('Code to run when the component is removed from the DOM'); + } + } + + view() { + // In mithril 0, you could skip redrawing a component (or part of a component) by returning a subtree retain directive. + // See https://mithril.js.org/archive/v0.2.5/mithril.render.html#subtree-directives + // dontRedraw is a substitute for logic; usually, this is used together with SubtreeRetainer. + if (dontRedraw()) return { subtree: 'retain' }; + + return

Hello World!

; + } +} + +class NewMithrilComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + oncreate(vnode) { + super.oncreate(vnode); + + console.log('Code to run when components are first created and attached to the DOM'); + } + + onbeforeupdate(vnode, oldVnode) { + super.onbeforeupdate(vnode); + + console.log('Code to run BEFORE diffing / redrawing components on every redraw'); + + // In mithril 2, if we want to skip diffing / redrawing a component, we return "false" in its onbeforeupdate lifecycle hook. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeupdate + // This is also typically used with SubtreeRetainer. + if (dontRedraw()) return false; + } + + onupdate(vnode) { + // Unlike config, this does NOT run when components are first attached. + // Some code might need to be replicated between oncreate and onupdate. + console.log('Code to run on every redraw AFTER the DOM is updated.'); + } + + onbeforeremove(vnode) { + // This is run before components are removed from the DOM. + // If a promise is returned, the DOM element will only be removed when the + // promise completes. It is only called on the top-level component that has + // been removed. It has no equivalent in Mithril 0.2. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeremove + return Promise.resolve(); + } + + onremove(vnode) { + console.log('Code to run when the component is removed from the DOM'); + } +} +``` + +#### Children vs Text Nodes + +In Mithril 0.2, every child of a vnode is another vnode, stored in `vnode.children`. For Mithril 2, as a performance optimization, vnodes with a single text child now store that text directly in `vnode.text`. For developers, that means that `vnode.children` might not always contain the results needed. Luckily, text being stored in `vnode.text` vs `vnode.children` will be the same each time for a given component, but developers should be aware that at times, they might need to use `vnode.text` and not `vnode.children`. + +Please see [the mithril documentation](https://mithril.js.org/vnodes.html#structure) for more information on vnode structure. + +#### Routing API + +Mithril 2 introduces a few changes in the routing API. Most of these are quite simple: + +- `m.route()` to get the current route has been replaced by `m.route.get()` +- `m.route(NEW_ROUTE)` to set a new route has been replaced by `m.route.set(NEW_ROUTE)` +- When registering new routes, a component class should be provided, not a component instance. + +Per esempio: + +```js +// Mithril 0.2 +app.routes.new_page = { path: '/new', component: NewPage.component() } + +// Mithril 2.0 +app.routes.new_page = { path: '/new', component: NewPage } +``` + +Additionally, the preferred way of defining an internal (doesn't refresh the page when clicked) link has been changed. The `Link` component should be used instead. + +```js +// Mithril 0.2 +Link Content + +// Mithril 2 +import Link from 'flarum/components/Link'; + +Link Content +``` + +You can also use `Link` to define external links, which will just render as plain `Children` html links. + +For a full list of routing-related changes, please see [the mithril documentation](https://mithril.js.org/migration-v02x.html). + +#### Redraw API + +Mithril 2 introduces a few changes in the redraw API. Most of these are quite simple: + +- Instead of `m.redraw(true)` for synchronous redraws, use `m.redraw.sync()` +- Instead of `m.lazyRedraw()`, use `m.redraw()` + +Remember that Mithril automatically triggers a redraw after DOM event handlers. The API for preventing a redraw has also changed: + +```js +// Mithril 0.2 + + +// Mithril 2 + +``` + +#### AJAX + +The `data` parameter of `m.request({...})` has been split up into `body` and `params`. + +For examples and other AJAX changes, see [the mithril documentation](https://mithril.js.org/migration-v02x.html#mrequest). + +#### Promises + +`m.deferred` has been removed, native promises should be used instead. Per esempio: + +```js +// Mithril 0.2 +const deferred = m.deferred(); + +app.store.find('posts').then(result => deferred.resolve(result)); + +return deferred.promise; + +// Mithril 2 +return app.store.find('posts'); +``` + +#### Component instances should not be stored + +Due to optimizations in Mithril's redrawing algorithms, [component instances should not be stored](https://mithril.js.org/components.html#define-components-statically,-call-them-dynamically). + +So whereas before, you might have done something like: + +```js +class ChildComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return

{this.counter}

; + } +} +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.child = new ChildComponent(); + } + + view() { + return ( +
+ + {this.child.render()} +
+ ) + } +} +``` + +That will no longer work. In fact; the Component class no longer has a render method. + +Instead, any data needed by a child component that is modified by a parent component should be passed in as an attr. Per esempio: + +```js +class ChildComponent extends Component { + view() { + return

{this.attrs.counter}

; + } +} + +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return ( +
+ + +
+ ) + } +} +``` + +For more complex components, this might require some reorganization of code. For instance, let's say you have data that can be modified by several unrelated components. In this case, it might be preferable to create a POJO "state instance' for this data. These states are similar to "service" singletons used in Angular and Ember. Per esempio: + +```js +class Counter { + constructor() { + this._counter = 0; + } + + increaseCounter() { + this._counter += 1; + } + + getCount() { + return this._counter; + } +} + +app.counter = new Counter(); + +extend(HeaderSecondary.prototype, 'items', function(items) { + items.add('counterDisplay', +
+

Counter: {app.counter.getCount()}

+
+ ); +}) + +extend(HeaderPrimary.prototype, 'items', function(items) { + items.add('counterButton', +
+ +
+ ); +}) +``` + +This "state pattern" can be found throughout core. Some non-trivial examples are: + +- PageState +- SearchState and GlobalSearchState +- NotificationListState +- DiscussionListState + +### Changes in Core + +#### Modali + +Previously, modals could be opened by providing a `Modal` component instance: + +```js +app.modal.show(new LoginModal(identification: 'prefilledUsername')); +``` + +Since we don't store component instances anymore, we pass in the component class and any attrs separately. + +```js +app.modal.show(LoginModal, {identification: 'prefilledUsername'}); +``` + +The `show` and `close` methods are still available through `app.modal`, but `app.modal` now points to an instance of `ModalManagerState`, not of the `ModalManager` component. Any modifications by extensions should accordingly be done to `ModalManagerState`. + +#### Avvisi + +Previously, alerts could be opened by providing an `Alert` component instance: + +```js +app.alerts.show(new Alert(type: 'success', children: 'Hello, this is a success alert!')); +``` + +Since we don't store component instances anymore, we pass in a component class, attrs, children separately. The `show` method has 3 overloads: + +```js +app.alerts.show('Hello, this is a success alert!'); +app.alerts.show({type: 'success'}, 'Hello, this is a success alert!'); +app.alerts.show(Alert, {type: 'success'}, 'Hello, this is a success alert!'); +``` + +Additionally, the `show` method now returns a unique key, which can then be passed into the `dismiss` method to dismiss that particular alert. This replaces the old method of passing the alert instance itself to `dismiss`. + +The `show`, `dismiss`, and `clear` methods are still available through `app.alerts`, but `app.alerts` now points to an instance of `AlertManagerState`, not of the `AlertManager` component. Any modifications by extensions should accordingly be done to `AlertManagerState`. + +#### Composer + +Since we don't store a component instances anymore, a number of util methods from `Composer`, `ComposerBody` (and it's subclasses), and `TextEditor` have been moved onto `ComposerState`. + +For `forum/components/Composer`, `isFullScreen`, `load`, `clear`, `show`, `hide`, `close`, `minimize`, `fullScreen`, and `exitFullScreen` have been moved to `forum/states/ComposerState`. They all remain accessible via `app.composer.METHOD` + +A `bodyMatches` method has been added to `forum/states/ComposerState`, letting you check whether a certain subclass of `ComposerBody` is currently open. + +Various input fields are now stored as [Mithril Streams](https://mithril.js.org/stream.html) in `app.composer.fields`. For instance, to get the current composer content, you could use `app.composer.fields.content()`. Previously, it was available on `app.composer.component.content()`. **This is a convention that `ComposerBody` subclasses that add inputs should follow.** + +`app.composer.component` is no longer available. + +- Instead of `app.composer.component instanceof X`, use `app.composer.bodyMatches(X)`. +- Instead of `app.composer.component.props`, use `app.composer.body.attrs`. +- Instead of `app.composer.component.editor`, use `app.composer.editor`. + +For `forum/components/TextEditor`, the `setValue`, `moveCursorTo`, `getSelectionRange`, `insertAtCursor`, `insertAt`, `insertBetween`, `replaceBeforeCursor`, `insertBetween` methods have been moved to `forum/components/SuperTextarea`. + +Also for `forum/components/TextEditor`, `this.disabled` is no longer used; `disabled` is passed in as an attr instead. It may be accessed externally via `app.composer.body.attrs.disabled`. + +Similarly to Modals and Alerts, `app.composer.load` no longer accepts a component instance. Instead, pass in the body class and any attrs. For instance, + +```js +// Mithril 0.2 +app.composer.load(new DiscussionComposer({user: app.session.user})); + +// Mithril 2 +app.composer.load(DiscussionComposer, {user: app.session.user}) +``` + +Finally, functionality for confirming before unloading a page with an active composer has been moved into the `common/components/ConfirmDocumentUnload` component. + +#### Widget and DashboardWidget + +The redundant `admin/components/Widget` component has been removed. `admin/components/DashboardWidget` should be used instead. + +#### NotificationList + +For `forum/components/NotificationList`, the `clear`, `load`, `loadMore`, `parseResults`, and `markAllAsRead` methods have been moved to `forum/states/NotificationListState`. + +Methods for `isLoading` and `hasMoreResults` have been added to `forum/states/NotificationListState`. + +`app.cache.notifications` is no longer available; `app.notifications` (which points to an instance of `NotificationListState`) should be used instead. + +#### Checkbox + +Loading state in the `common/components/Checkbox` component is no longer managed through `this.loading`; it is now passed in as a prop (`this.attrs.loading`). + +#### Preference Saver + +The `preferenceSaver` method of `forum/components/SettingsPage` has been removed without replacement. This is done to avoid saving component instances. Instead, preferences should be directly saved. Per esempio: + +```js +// Old way +Switch.component({ + children: app.translator.trans('core.forum.settings.privacy_disclose_online_label'), + state: this.user.preferences().discloseOnline, + onchange: (value, component) => { + this.user.pushAttributes({ lastSeenAt: null }); + this.preferenceSaver('discloseOnline')(value, component); + }, +}) + +// Without preferenceSaver +Switch.component({ + children: app.translator.trans('core.forum.settings.privacy_disclose_online_label'), + state: this.user.preferences().discloseOnline, + onchange: (value) => { + this.discloseOnlineLoading = true; + + this.user.savePreferences({ discloseOnline: value }).then(() => { + this.discloseOnlineLoading = false; + m.redraw(); + }); + }, + loading: this.discloseOnlineLoading, +}) +``` + +A replacement will eventually be introduced. + +#### DiscussionListState + +For `forum/components/DiscussionList`, the `requestParams`, `sortMap`, `refresh`, `loadResults`, `loadMore`, `parseResults`, `removeDiscussion`, and `addDiscussion` methods have been moved to `forum/states/DiscussionListState`. + +Methods for `hasDiscussions`, `isLoading`, `isSearchResults`, and `empty` have been added to `forum/states/DiscussionListState`. + +`app.cache.discussions` is no longer available; `app.discussions` (which points to an instance of `DiscussionListState`) should be used instead. + +#### PageState + +`app.current` and `app.previous` no longer represent component instances, they are now instances of the `common/states/PageState` class. This means that: + +- Instead of `app.current instanceof X`, use `app.current.matches(X)` +- Instead of `app.current.PROPERTY`, use `app.current.get('PROPERTY')`. Please note that all properties must be exposed EXPLICITLY via `app.current.set('PROPERTY', VALUE)`. + +#### PostStream + +Logic from `forum/components/PostStreamScrubber`'s `update` method has been moved to `forum/components/PostStream`'s `updateScrubber` method. + +For `forum/components/PostStream`, the `update`, `goToFirst`, `goToLast`, `goToNumber`, `goToIndex`, `loadNearNumber`, `loadNearIndex`, `loadNext`, `loadPrevious`, `loadPage`, `loadRange`, `show`, `posts`, `reset`, `count`, and `sanitizeIndex` methods have been moved to `forum/states/PostStreamState`. + +Methods for `disabled` and `viewingEnd` have been added to `forum/states/PostStreamState`. + +#### SearchState and GlobalSearchState + +As with other components, we no longer store instances of `forum/components/Search`. As such, every `Search` component instance should be paired with a `forum/states/SearchState` instance. + +At the minimum, `SearchState` contains the following methods: + +- getValue +- setValue +- clear +- cache (adds a searched value to cache, meaning that we don't need to search for its results again) +- isCached (checks if a value has been searched for before) + +All of these methods have been moved from `Search` to `SearchState`. Additionally, Search's `stickyParams`, `params`, `changeSort`, `getInitialSearch`, and `clearInitialSearch` methods have been moved to `forum/states/GlobalSearchState`, which is now available via `app.search`. + +To use a custom search, you'll want to: + +1. Possibly create a custom subclass of `SearchState` +2. Create a custom subclass of `Search`, which overrides the `selectResult` method to handle selecting results as needed by your use case, and modify the `sourceItems` methods to contain the search sources you need. + +#### moment -> dayjs + +The `moment` library has been removed, and replaced by the `dayjs` library. The global `moment` can still be used for now, but is deprecated. `moment` and `dayjs` have very similar APIs, so very few changes will be needed. Please see the dayjs documentation [for more information](https://day.js.org/en/) on how to use it. + +#### Subtree Retainer + +`SubtreeRetainer` is a util class that makes it easier to avoid unnecessary redraws by keeping track of some pieces of data. When called, it checks if any of the data has changed; if not, it indicates that a redraw is not necessary. + +In mithril 0.2, its `retain` method returned a [subtree retain directive](https://mithril.js.org/archive/v0.1.25/mithril.render.html#subtree-directives) if no redraw was necessary. + +In mithril 2, we use its `needsRebuild` method in combination with `onbeforeupdate`. Per esempio: + +```js +class CustomComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + this.showContent = false; + + this.subtree = new SubtreeRetainer( + () => this.showContent, + ) + } + + onbeforeupdate() { + // If needsRebuild returns true, mithril will diff and redraw the vnode as usual. Otherwise, it will skip this redraw cycle. + // In this example, this means that this component and its children will only be redrawn when extra content is toggled. + return this.subtree.needsRebuild(); + } + + view(vnode) { + return
+ +

Hello World!{this.showContent ? ' Extra Content!' : ''}

+
; + } +} +``` + +#### attrs() method + +Previously, some components would have an attrs() method, which provided an extensible way to provide attrs to the top-level child vnode returned by `view()`. For instance, + +```js +class CustomComponent extends Component { + view() { + return

Hello World!

; + } + + attrs() { + return { + className: 'SomeClass', + onclick: () => console.log('click'), + }; + } +} +``` + +Since `this.attrs` is now used for attrs passed in from parent components, `attrs` methods have been renamed to `elementAttrs`. + +#### Children and .component + +Previously, an element could be created with child elements by passing those in as the `children` prop: + +```js +Button.component({ + className: 'Button Button--primary', + children: 'Button Text' +}); +``` + +This will no longer work, and will actually result in errors. Instead, the 2nd argument of the `component` method should be used: + +```js +Button.component({ + className: 'Button Button--primary' +}, 'Button Text'); +``` + +Children can still be passed in through JSX: + +```js + +``` + +#### Tag attr + +Because mithril uses 'tag' to indicate the actual html tag (or component class) used for a vnode, you can no longer pass `tag` as an attr to components extending Flarum's `Component` helper class. The best workaround here is to just use another name for this attr. + +#### affixSidebar + +The `affixSidebar` util has been removed. Instead, if you want to affix a sidebar, wrap the sidebar code in an `AffixedSidebar` component. For instance, + +```js +class OldWay extends Component { + view() { + return
+
+
+ +
Actual Page Content
+
+
+
; + } +} + +class NewWay extends Component { + view() { + return
+
+
+ + + +
Actual Page Content
+
+
+
; + } +} +``` + +#### Fragment + +**Warning: For Advanced Use Only** + +In some rare cases, we want to have extremely fine grained control over the rendering and display of some significant chunks of the DOM. These are attached with `m.render`, and do not experience automated redraws. Current use cases in core and bundled extensions are: + +- The "Reply" button that shows up when selecting text in a post +- The mentions autocomplete menu that shows up when typing +- The emoji autocomplete menu that shows up when typing + +For this purpose, we provide a helper class (`common/Fragment`), of which you can create an instance, call methods, and render via `m.render(DOM_ROOT, fragmentInstance.render())`. The main benefit of using the helper class is that it allows you to use lifecycle methods, and to access the underlying DOM via `this.$()`, like you would be able to do with a component. + +This should only be used when absolutely necessary. If you are unsure, you probably don't need it. If the goal is to not store component instances, the "state pattern" as described above is preferable. + +### Required Frontend Changes Recap + +Each of these changes has been explained above, this is just a recap of major changes for your convenience. + +- Component Methods: + - `view()` -> `view(vnode)` + - Lifecycle + - `init()` -> `oninit(vnode)` + - `config()` -> Lifecycle hooks `oncreate(vnode)` / `onupdate(vnode)` + - `context.onunload()` -> `onremove()` + - `SubtreeRetainer` -> `onbeforeupdate()` + - if present, `attrs()` method needs to be renamed -> convention `elementAttrs()` + - building component with `MyComponent.component()` -> `children` is now second parameter instead of a named prop/attr (first argument) -> JSX preferred +- Routing + - `m.route()` -> `m.route.get()` + - `m.route(name)` -> `m.route.set(name)` + - register routes with page class, not instance + - special case when passing props + - `` -> `` +- AJAX + - `m.request({...})` -> `data:` key split up into `body:` and `params:` + - `m.deferred` -> native `Promise` +- Redrawing + - `m.redraw(true)` -> `m.redraw.sync()` + - `m.redraw.strategy('none')` -> `e.redraw = false` in event handler + - `m.lazyRedraw()` -> `m.redraw()` + +#### Deprecated changes + +For the following changes, we currently provide a backwards-compatibility layer. This will be removed in time for the stable release. The idea is to let you release a new version that's compatible with Beta 14 to your users as quickly as possible. When you have taken care of the changes above, you should be good to go. For the following changes, we have bought you time until the stable release. Considering you have to make changes anyway, why not do them now? + +- `this.props` -> `this.attrs` +- static `initProps()` -> static `initAttrs()` +- `m.prop` -> `flarum/utils/Stream` +- `m.withAttr` -> `flarum/utils/withAttr` +- `moment` -> `dayjs` + +## Backend (PHP) + +### New Features + +#### Extension Dependencies + +Some extensions are based on, or add features to, other extensions. Prior to this release, there was no way to ensure that those dependencies were enabled before the extension that builds on them. Now, you cannot enable an extension unless all of its dependencies are enabled, and you cannot disable an extension if there are other enabled extensions depending on it. + +So, how do we specify dependencies for an extension? Well, all you need to do is add them as composer dependencies to your extension's `composer.json`! For instance, if we have an extension that depends on Tags and Mentions, our `composer.json` will look like this: + +```json +{ + "name": "my/extension", + "description": "Cool New Extension", + "type": "flarum-extension", + "license": "MIT", + "require": { + "flarum/core": "^0.1.0-beta.14", + "flarum/tags": "^0.1.0-beta.14", // Will mark tags as a dependency + "flarum/mentions": "^0.1.0-beta.14", // Will mark mentions as a dependency + } + // other config +} +``` + +#### View Extender + +Previously, when extensions needed to register Laravel Blade views, they could inject a view factory in `extend.php` and call it's `addNamespace` method. For instance, + +```php +// extend.php +use Illuminate\Contracts\View\Factory; + +return [ + function (Factory $view) { + $view->addNamespace(NAME, RELATIVE PATH); + } +] +``` + +This should NOT be used, as it will break views for all extensions that boot after yours. Instead, the `View` extender should be used: + +```php +// extend.php +use Flarum\Extend\View; + +return [ + (new View)->namespace(NAME, RELATIVE PATH); +] +``` + +#### Application and Container + +Although Flarum uses multiple components of the Laravel framework, it is not a pure Laravel system. In beta 14, the `Flarum\Foundation\Application` class no longer implements `Illuminate\Contracts\Foundation\Application`, and no longer inherits `Illuminate\Container\Container`. Several things to note: + +- The `app` helper now points to an instance of `Illuminate\Container\Container`, not `Flarum\Foundation\Application`. You might need to resolve things through the container before using them: for instance, `app()->url()` will no longer work; you'll need to resolve or inject an instance of `Flarum\Foundation\Config` and use that. +- Injected or resolved instances of `Flarum\Foundation\Application` can no longer resolve things through container methods. `Illuminate\Container\Container` should be used instead. +- Not all public members of `Illuminate\Contracts\Foundation\Application` are available through `Flarum\Foundation\Application`. Please refer to our [API docs on `Flarum\Foundation\Application`](https://api.docs.flarum.org/php/master/flarum/foundation/application) for more information. + +#### Other Changes + +- We are now using Laravel 6. Please see [Laravel's upgrade guide](https://laravel.com/docs/6.x/upgrade) for more information. Please note that we do not use all of Laravel. +- Optional params in url generator now work. For instance, the url generator can now properly generate links to posts in discussions. +- A User Extender has been added, which replaces the deprecated `PrepareUserGroups` and `GetDisplayName` events. +- Error handler middleware can now be manipulated by the middleware extender through the `add`, `remove`, `replace`, etc methods, just like any other middleware. +- `Flarum/Foundation/Config` and `Flarum/Foundation/Paths` can now be injected where needed; previously their data was accessible through `Flarum/Foundation/Application`. + +### Deprecations + +- `url` provided in `config.php` is now an array, accessible via `$config->url()`, for an instance of `Config` - [PR](https://github.com/flarum/core/pull/2271#discussion_r475930358) +- AssertPermissionTrait has been deprecated - [Issue](https://github.com/flarum/core/issues/1320) +- Global path helpers and path methods of `Application` have been deprecated, the injectable `Paths` class should be used instead - [PR](https://github.com/flarum/core/pull/2155) +- `Flarum\User\Event\GetDisplayName` has been deprecated, the `displayNameDriver` method of the `User` extender should be used instead - [PR](https://github.com/flarum/core/pull/2174) + +### Removals + +- Do NOT use the old closure notation for configuring view namespaces. This will break all extensions that boot after your extension. The `View` extender MUST be used instead. +- app()->url() will no longer work: [`Flarum\Http\UrlGenerator`](routes.md) should be injected and used instead. An instance of `Flarum\Http\UrlGenerator` is available in `blade.php` templates via `$url`. +- As a part of the Laravel 6 upgrade, the [`array_` and `str_` helpers](https://laravel.com/docs/6.x/upgrade#helpers) have been removed. +- The Laravel translator interface has been removed; the Symfony translator interface should be used instead: `Symfony\Component\Translation\TranslatorInterface` +- The Mandrill mail driver is no longer provided in Laravel 6, and has been removed. +- The following events deprecated in Beta 13 [have been removed](https://github.com/flarum/core/commit/7d1ef9d89161363d1c8dea19cf8aebb30136e9e3#diff-238957b67e42d4e977398cd048c51c73): + - `AbstractConfigureRoutes` + - `ConfigureApiRoutes` - Use the `Routes` extender instead + - `ConfigureForumRoutes` - Use the `Frontend` or `Routes` extenders instead + - `ConfigureLocales` - Use the `LanguagePack` extender instead + - `ConfigureModelDates` - Use the `Model` extender instead + - `ConfigureModelDefaultAttributes` - Use the `Model` extender instead + - `GetModelRelationship` - Use the `Model` extender instead + - `Console\Event\Configuring` - Use the `Console` extender instead + - `BioChanged` - User bio has not been a core feature for several releases diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md new file mode 100644 index 000000000..c5763344c --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md @@ -0,0 +1,60 @@ +# Aggiornamenti Beta 15 + +La Beta 15 presenta molti nuovi extender, una riprogettazione totale del dashboard di amministrazione e molte altre interessanti funzionalità per le estensioni. Come sempre, abbiamo fatto del nostro meglio per fornire livelli di compatibilità con le versioni precedenti e consigliamo di abbandonare i sistemi obsoleti il prima possibile per rendere le estensioni più stabili. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Nuove funzionalità / deprecazioni + +### Extender + +- `Flarum\Api\Event\WillGetData` e `Flarum\Api\Event\WillSerializeData` sono stati deprecati, l'extender `ApiController` va utilizzato al suo posto +- `Flarum\Api\Event\Serializing` e `Flarum\Event\GetApiRelationship` sono stati deprecati, l'extender `ApiSerializer` va utilizzato al suo posto +- `Flarum\Formatter\Event\Parsing` è obsoleto, il metodo `parse` di `Formatter` va utilizzato al suo posto +- `Flarum\Formatter\Event\Rendering` è obsoleto, il metodo `render` di `Formatter` va utilizzato al suo posto +- `Flarum\Notification\Event\Sending` è obsoleto, il metodo `driver` di `Notification` va utilizzato al suo posto + - Si noti che il nuovo sistema di driver di notifica non è un analogo esatto del vecchio evento `Sending`, poiché può solo aggiungere nuovi driver, non modificare la funzionalità del driver di avviso della campana di notifica predefinito. Se l'estensione deve modificare ** come ** o ** a chi ** vengono inviate le notifiche, potrebbe essere necessario sostituire `Flarum\Notification\NotificationSyncer`. +- `Flarum\Event\ConfigureNotificationTypes` è obsoleto, il metodo `type` di `Notification` va utilizzato al suo posto +- `Flarum\Event\ConfigurePostTypes` è obsoleto, il metodo `type` di `Post` va utilizzato al suo posto +- `Flarum\Post\Event\CheckingForFlooding` è ormai obsoleto come `Flarum\Post\Floodgate`. Sono stati sostituiti con un sistema di limitazione basato su middleware che si applica a TUTTE le richieste a / api / * e possono essere configurati tramite il `ThrottleApi`. Per favore guarda la documentazione [limitazioni API](api-throttling.md) per informazioni. +- `Flarum\Event\ConfigureUserPreferences` è ormai obsoleto, il metodo `registerPreference` di `User` va utilizzato al suo posto +- `Flarum\Foundation\Event\Validating` è ormai obsoleto, il metodo `configure` di `Validator` va utilizzato al suo posto + +- Il sistema delle politiche è stato leggermente rielaborato per essere più intuitivo. In precedenza, i criteri contenevano sia i criteri effettivi, che determinano se un utente può eseguire alcune capacità, sia gli ambiti di visibilità del modello, che consentivano un'efficace limitazione delle query solo agli elementi a cui gli utenti hanno accesso. Guarda [documentazione sulle autorizzazioni](authorization.md) per maggiori informazioni su questo sistema. Ora: + - `Flarum\Event\ScopeModelVisibility` è ormai obsoleto. Nuovi scopers possono essere registrati tramite l'extender `ModelVisibility`, e ogni query `Eloquent\Builder` può essere richiamata dal metodo `whereVisibleTo`, con l'abilità in questione come secondo argomento opzionale (il valore predefinito è `view`). + - `Flarum\Event\GetPermission` è ormai obsoleto. Le policy possono essere registrate tramite extender `Policy`. `Flarum\User\User::can` non è cambiato. Si prega di notare che le nuove policy devono restituire uno dei valori `$this->allow()`, `$this->deny()`, `$this->forceAllow()`, `$this->forceDeny()`, non booleano. + +- L'extender `ModelUrl` è stato aggiunto, consentendo la registrazione di nuovi driver di slug. Ciò accompagna il nuovo sistema di slug di Flarum, che consente alle estensioni di definire strategie personalizzate per i modelli. L'estensore supporta modelli al di fuori del nucleo Flarum. Si prega di consultare il nostro file [model slugging](slugging.md) per informazioni. +- L'extender `Settings` è stato aggiunto, il metodo `serializeToForum` semplifica la serializzazione di un'impostazione nel forum. +- L'extender `ServiceProvider` è stato aggiunto. Questo dovrebbe essere usato con estrema cautela solo per casi d'uso avanzati, dove non ci sono alternative. Tieni presente che il livello del fornitore di servizi non è considerato API pubblica ed è soggetto a modifiche in qualsiasi momento, senza preavviso. + +### Pannello Amministrazione ridisegnato + +La dashboard dell'amministratore è stata completamente ridisegnata, con l'obiettivo di barre di navigazione per ogni estensione. Anche l'API per le estensioni per registrare impostazioni, autorizzazioni e pagine personalizzate è stata notevolmente semplificata. Ora puoi anche aggiornare la tua estensione `composer.json` per fornire link per finanziamenti, supporto, siti web e così via che verranno visualizzati nella pagina di amministrazione della tua estensione. Please see [our Admin JS documentation](admin.md) for more information on how to use the new system. + +### Altre feauture nuove + +- Sul backend, il nome del percorso è ora disponibile tramite `$request->getAttribute('routeName')`, e per il middleware che viene eseguito dopo `Flarum\Http\Middleware\ResolveRoute.php`. +- `Flarum\Api\Controller\UploadImageController.php` può ora essere utilizzato come classe base per i controller che caricano immagini (come per il logo e la favicon). +- AIl ripristino automatico dello scorrimento del browser ora può essere disabilitato per le singole pagine [vedere la nostra documentazione del frontend per maggiori informazioni](frontend-pages.md). + +## Cambiamenti decisivi + +- I seguenti layer BC deprecati del frontend sono stati rimossi: + - `momentjs` non funziona più come alias per `dayjs` + - `this.props` e `this.initProps` non più alias di `this.attrs` e `this.initAttrs` per la classe base `Component` + - `m.withAttr` e `m.stream` non più alias di `flarum/utils/withAttr` e `flarum/utils/Stream` + - `app.cache.discussionList` è stato rimosso + - `this.content` e `this.editor` sono stati rimossi da `ComposerBody` + - `this.component`, `this.content`, e `this.value` sono stati rimossi da `ComposerState` +- I seguenti layer BC back-end deprecati sono stati rimossi: + - `publicPath`, `storagePath`, e `vendorPath` di `Flarum\Foundation\Application` sono stati rimossi + - `base_path`, `public_path`, e `storage_path` sono stati rimossi + - `getEmailSubject` di `Flarum\Notification\MailableInterface` DEVE ora prendere un'istanza di traduttore come argomento + - `Flarum\User\AssertPermissionTrait` è stato rimosso, i metodi analoghi su `Flarum\User\User` andranno utilizzati al suo posto + - `Flarum\Event\PrepareUserGroups` è stato rimosso, usa invece l'extender `User` + - `Flarum\User\Event\GetDisplayName` è stato rimosso, usa invece l'extender `User` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md new file mode 100644 index 000000000..0ab1aa8eb --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md @@ -0,0 +1,138 @@ +# Aggiornamenti per Beta 16 + +La Beta 16 finalizza l'API extender PHP, introduce una libreria di test e le tipizzazioni JS, passa all'utilizzo di namespace per le importazioni JS, aumenta la robustezza della dipendenza dalle estensioni e consente l'override deli percorsi, tra le altre funzionalità. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Frontend + +- È stata introdotta una nuova astrazione del driver dell'editor, che consente alle estensioni di sostituire l'editor predefinito basato sull'area di testo con soluzioni più avanzate. +- I componenti `TextEditor` e `TextEditorButton`, così come `BasicEditorDriver` (che rimpiazza `SuperTextarea`) è stato spostato da `forum` a `common`. +- I namespace `forum`, `admin`, e `common` dovrebbero essere usati durante l'importazione. Quind invece di `import Component from 'flarum/Component'`, utilizzate `import Component from 'flarum/common/Component`. Il supporto per i vecchi stili di importazione sarà deprecato con la versione stabile e rimosso con Flarum 2.0. +- È stata rilasciata una libreria di digitazione per supportare il completamento automatico dell'editor per lo sviluppo del frontend, installabile tramite `npm install --save-dev flarum@0.1.0-beta.16`. +- Le categorie di estensioni sono state semplificate fino a `feature`, `theme`, e `language`. + +## Backend + +### Estensori + +- Tutti gli extender che supportano callback / chiusure ora supportano funzioni globali come `'boolval'` e funzioni array-type come `[ClassName::class, 'methodName']`. +- L'estensore `Settings` e metodo `serializeToFrontend` ora supporta un valore predefinito come quarto argomento. +- L'estensore `Event` ora supporta la registrazione di abbonati a più eventi contemporaneamente tramite metodo `subscribe`. +- L'estensore `Notification` utilizza ora il metodo `beforeSending`, che consente di modificare l'elenco dei destinatari prima che venga inviata una notifica. +- Il metodo `mutate` di `ApiSerializer` è ora deprecato, e rinominato come `attributes`. +- Il metodo `remove` negli estensori `Route` e `Frontend` può essere utilizzato per rimuovere (e quindi sostituire) le rotte. +- L'estensore `ModelPrivate` rimpiazza l'evento `GetModelIsPrivate`, ormai deprecato. +- I metodi sull'estensore `Auth` rimpiazzano l'evento `CheckingPassword`, ormai deprecato. +- Tutti gli eventi relativi alla ricerca sono ora deprecati a favore di estensori quali `SimpleFlarumSearch` e `Filter`; spiegato meglio qui sotto. + +### Laravel e Symfony + +Aggiornamenti beta 16 dalla v6.x alla v8.x dei componenti Laravel e dalla v4 alla v5 dei componenti Symfony. Consulta le rispettive guide all'upgrade di ciascuna per le modifiche che potresti dover apportare alle tue estensioni. La modifica più sostanziale è la deprecazione di `Symfony\Component\Translation\TranslatorInterface` in favore di `Symfony\Contracts\Translation\TranslatorInterface`. Il primo verrà rimosso nella beta 17. + +### Funzioni Helper + +I rimanenti helper `app` e `event` sono ora deprecati. `app` è stato rimpiazzato con `resolve`. + +Poiché alcune estensioni Flarum utilizzano librerie Laravel che presumono l'esistenza di alcuni helper globali, abbiamo ricreato alcuni helper comunemente usati nel pacchetto [flarum/laravel-helpers](https://github.com/flarum/laravel-helpers). Questi helper NON dovrebbero essere usati direttamente nel codice di estensione Flarum; sono disponibili in modo che le librerie basate su Laravel che si aspettano che esistano non funzionino male. + +### Cambiamenti alla Ricerca + +Come parte dei nostri continui sforzi per rendere il sistema di ricerca di Flarum più flessibile, abbiamo rifattorizzato parecchio codice nella beta 16. In particolare, il filtraggio e la ricerca sono ora trattati come meccanismi diversi e hanno condutture ed estensori separati. In sostanza, se una query ha `filter[q]` come parametro, verrà considerato come una ricerca e tutti gli altri parametri del filtro verranno ignorati. In caso contrario, verrà gestito dal sistema di filtraggio. Ciò consentirà alla fine di gestire le ricerche da driver alternativi (forniti dalle estensioni), come ElasticSearch, senza impattare i filtri (es. caricamento discussioni recenti). Le classi comuni a entrambi i sistemi sono state spostate sotto il namespace `Query`. + +Le implementazioni di filtro e ricerca predefinita di Core (denominate SimpleFlarumSearch) sono abbastanza simili, poiché entrambe sono alimentate dal database. L'API controller `List` richiama i metodi `search` / `filter` in una sottoclasse specifica delle risorse di `Flarum\Search\AbstractSearcher` o `Flarum\Filter\AbstractFilterer`. Gli argomenti sono un'istanza di `Flarum\Query\QueryCriteria`, oltre a informazioni su ordinamento, offset e limite. Entrambi i sistemi restituiscono un'istanza di `Flarum\Query\QueryResults`, che è effettivamente un involucro attorno a una collezione di modelli Eloquent. + +Anche i sistemi predefiniti sono in qualche modo simili nella loro implementazione. `Filterer`applica filtri (implementando `Flarum\Filter\FilterInterface`) in base ai parametri della query nel modulo `filter[FILTER_KEY] = FILTER_VALUE` (o `filter[-FILTER_KEY] = FILTER_VALUE` per filtri negati). SimpleFlarumSearch `Searcher` divide il parametro `filter[q]` da spazi in "termini", applica Gambits (implementando `Flarum\Search\GambitInterface`) che corrispondono ai termini e quindi applicano "Fulltext Gambit" per cercare in base a "termini" che non corrispondono ad un "auxiliary gambit". Entrambi i sistemi applicano quindi l'ordinamento, un offset e un limite di conteggio dei risultati e consentono alle estensioni di modificare il risultato della query tramite `searchMutators` o `filterMutators`. + +Le estensioni aggiungono "gambits" e "search mutators" per classi `Searcher` tramite estensore `SimpleFlarumSearch`. Possono aggiungere filtri a classi `Filterer` tramite estensore`Filter`. + +Per quanto riguarda l'aggiornamento, tieni presente quanto segue: + +- Cerca le mutazioni registrate con eventi `Searching`, per le discussioni e gli utenti verranno applicate le ricerche durante la fase di mutazione della ricerca tramite uno strato BC temporaneo. NON verranno applicati ai filtri. Questo è un cambiamento decisivo. Questi eventi sono stati deprecati. +- Search gambits registrati con eventi `ConfigureUserGambits` e `ConfigureDiscussionGambits` verrà applicato al ricercatore tramite un layer BC temporaneo. NON verranno applicati ai filtri. Questo è un cambiamento decisivo. Questi eventi sono stati deprecati. +- Filtri post registrati tramite eventi `ConfigurePostsQuery` verrà applicato ai filtri dei post tramite un layer BC temporaneo. Quell'evento è stato deprecato. + +### Libreria di test + +Il pacchetto `flarum/testing` fornisce utilità per test backend automatizzati basati su PHPUnit. Vedi [documentazione test](testing.md) per info. + +### Dipendenze opzionali + +La Beta 15 ha introdotto le "dipendenze delle estensioni", che richiedono tutte le estensioni elencate in `composer.json` e nella sezione `require` da abilitare prima che la tua estensione possa essere utilizzata. + +Con la beta 16, puoi specificare "dipendenze opzionali" elencando i nomi dei pacchetti del composer come un array nella tua estensione `extra.flarum-extension.optional-dependencies`. Qualsiasi dipendenza facoltativa abilitata verrà avviata prima dell'estensione, ma non è necessaria per l'abilitazione di quest'ultima. + +### Access Token e cambiamenti all'autenticazione + +#### Cambiamenti Estensioni API + +La firma per vari metodi relativi all'autenticazione è stata modificata in `$token` come parametro invece di `$userId`. Altre modifiche sono il risultato del passaggio da `$lifetime` a `$type` + +- `Flarum\Http\AccessToken::generate($userId)` non accetta più `$lifetime` come secondo parametro. Il parametro è stato mantenuto per compatibilità con le versioni precedenti ma non ha alcun effetto. Verrà rimosso nella beta 17. +- `Flarum\Http\RememberAccessToken::generate($userId)` dovrebbe essere usato per creare token di accesso da ricordare. +- `Flarum\Http\DeveloperAccessToken::generate($userId)` dovrebbe essere utilizzato per creare token di accesso sviluppatore (non scadono). +- `Flarum\Http\SessionAccessToken::generate()` può essere utilizzato come alias per `Flarum\Http\AccessToken::generate()`. Verrà deprecato `AccessToken::generate()` in futuro. +- `Flarum\Http\Rememberer::remember(ResponseInterface $response, AccessToken $token)`: passare `AccessToken` è stato deprecato. Passa un'istanza di `RememberAccessToken` al suo posto. Come livello di compatibilità temporaneo, il passaggio di qualsiasi altro tipo di token lo convertirà in un token di ricordo. Nella beta 17 la firma del metodo cambierà per accettare solo `RememberAccessToken`. +- `Flarum\Http\Rememberer::rememberUser()` è deprecata. Invece dovresti creare / recuperare un token manualmente con `RememberAccessToken::generate()` e passarlo a `Rememberer::remember()` +- `Flarum\Http\SessionAuthenticator::logIn(Session $session, $userId)` come secondo parametro è stato deprecato ed è stato sostituito con `$token`. Viene mantenuta la compatibilità con le versioni precedenti. Nella beta 17, la firma del secondo metodo del parametro cambierà in `AccessToken $token`. +- `AccessToken::generate()` ora salva il modello nel database prima di restituirlo. +- `AccessToken::find($id)` or `::findOrFail($id)` non può più essere utilizzato per trovare un token, perché la chiave primaria è stata modificata da `token` a `id`. Invece puoi utilizzare `AccessToken::findValid($tokenString)` +- Si consiglia di utilizzare `AccessToken::findValid($tokenString): AccessToken` o `AccessToken::whereValid(): Illuminate\Database\Eloquent\Builder` per trovare un token. Ciò consentirà automaticamente alla richiesta di restituire solo token validi. Sui forum con bassa attività questo aumenta la sicurezza poiché l'eliminazione automatica dei token obsoleti avviene in media solo ogni 50 richieste. + +#### Cambiamenti sessioni Symfony + +Se stai accedendo o manipolando direttamente l'oggetto sessione di Symfony, sono state apportate le seguenti modifiche: + +- L'attributo `user_id` non è più utilizzato. `access_token` è ora utilizzato al suo posto. È una stringa che mappa alla colonna `token` della tabella nel database `access_tokens`. + +Per recuperare l'utente corrente dall'interno di un'estensione Flarum, la soluzione ideale che era già presente in Flarum è quella di utilizzare `$request->getAttribute('actor')` che restituisce un istanza di `User` (quale potrebbe essere `Guest`) + +Per recuperare l'istanza del token da Flarum, puoi usare `Flarum\Http\AccessToken::findValid($tokenString)` + +Per recuperare i dati utente da un'applicazione non Flarum, dovrai effettuare una richiesta di database aggiuntiva per recuperare il token. L' user ID è presente come `user_id` nella tabella `access_tokens. + +#### Cambiamenti creazione Token + +La proprietà `lifetime` degli access token è stata rimossa. I token ora sono token di `session` con durata di 1 ora dopo l'ultima attività, o i token `session_remember` con 5 anni di vita dopo l'ultima attività. + +Il parametro `remember` precedentemente disponibile sull'endopoint `POST /login` è stato redo disponibile in `POST /api/token`. Non restituisce il cookie di memorizzazione stesso, ma il token restituito può essere utilizzato come cookie di memorizzazione. + +Il parametro `lifetime` di `POST /api/token` è stato deprecato e verrà rimosso in Flarum beta 17. È stata fornita una compatibilità con le versioni precedenti parziale laddove un valore `lifetime` con più di 3600 secondi viene interpretato come `remember=1`. Valori inferiori a 3600 secondi danno come risultato un normale token di non ricordo. + +Nuovi token `developer` tokens that don't expire have been introduced, che non scadono sono stati introdotti, tuttavia non possono essere attualmente creati tramite l'API REST. Gli sviluppatori possono creare token per sviluppatori da un'estensione utilizzando `Flarum\Http\DeveloperAccessToken::generate($userId)`. + +Se hai creato manualmente token nel database dall'esterno di Flarum, la colonna `type` è ora richiesta e deve contenere `session`, `session_remember` o `developer`. I token di tipo non riconosciuto non possono essere utilizzati per l'autenticazione, ma non verranno nemmeno eliminati dal garbage collector. In una versione futura le estensioni potranno registrare tipi di token di accesso personalizzati. + +#### Cambiamenti all'utilizzo dei token + +I [problemi di sicurezza in Flarum](https://github.com/flarum/core/issues/2075) causavano la non scadenza dei token. Ciò ha avuto un impatto sulla sicurezza limitato poiché i token sono caratteri lunghi e unici. Tuttavia, le integrazioni personalizzate che hanno salvato un token in un database esterno per un uso successivo potrebbero scoprire che i token non funzionano più se non sono stati utilizzati di recente. + +Se utilizzi token di accesso di breve durata per qualsiasi scopo, prendi nota del tempo di scadenza di 1 ora. La scadenza si basa sull'ora dell'ultimo utilizzo, quindi rimarrà valida finché continuerà ad essere utilizzata. + +A causa della grande quantità di token scaduti accumulati nel database e del fatto che la maggior parte dei token non è mai stata utilizzata più di una volta durante il processo di accesso, abbiamo scelto di eliminare tutti i token di accesso per una durata di 3600 secondi come parte della migrazione , Tutti i token rimanenti sono stati convertiti in `session_remember`. + +#### Ricorda cookie + +Il cookie di memorizzazione funziona ancora come prima, ma sono state apportate alcune modifiche che potrebbero interrompere implementazioni insolite. + +Ora accedi solo ai token creati con opzione `remember`. Qualsiasi altro tipo di token verrà ignorato. Ciò significa che se crei un token con `POST /api/token` e lo inserisci manualmente nel cookie, devi assicurati di aver impostato `remember=1` durante la sua creazione. + +#### Scadenza della sessione Web + +Nelle versioni precedenti di Flarum, una sessione poteva essere mantenuta in vita per sempre fino a quando i file della sessione di Symfony non venivano cancellati dal disco. + +Ora le sessioni sono collegate ai token di accesso. Un token in fase di eliminazione o in scadenza terminerà automaticamente la sessione web collegata. + +Un token collegato a una sessione Web verrà ora automaticamente eliminato dal database quando l'utente fa clic su Logout. Ciò impedisce il riutilizzo di qualsiasi token rubato, ma potrebbe interrompere l'integrazione personalizzata che in precedenza utilizzava un singolo token di accesso sia in una sessione Web che in qualcos'altro. + +### Varie + +- L'indirizzo IP è ora disponibile nelle richieste tramite `$request->getAttribute('ipAddress')` +- Le policy possono ora restituire `true` e `false` come alias per `$this->allow()` e `$this->deny()`, rispettivamente. +- I permessi `user.edit` sono stati divisi in `user.editGroups`, `user.editCredentials` (per email, username, e password), e `user.edit` (per altri attributi). +- Ci sono ora permessi (`bypassTagCounts`) che consentono agli utenti di ignorare i requisiti di conteggio dei tag. +- Flarum ora supporta PHP 7.3 - PHP 8.0, con supporto per PHP 7.2 ufficialmente abbandonato. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md new file mode 100644 index 000000000..0bce7f03e --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md @@ -0,0 +1,114 @@ +# Updating For Beta 8 + +All extensions will need to be refactored in order to work with beta 8. Here are the main things you will need to do in order to make your extension compatible. + +:::cautela + +This guide is not comprehensive. You may encounter some changes we haven't documented. If you need help, start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## PHP Namespaces + +Beta 8 comes with large changes to the overall structure of the PHP backend. You will need to look through [this list](https://discuss.flarum.org/d/6572-help-us-namespace-changes) of namespace changes and make changes to your extension accordingly. + +[This script](https://gist.github.com/tobyzerner/55e7c05c95404e5efab3a9e43799d375) can help you to automate most of the namespace changes. Of course, you should still test your extension after running the script as it may miss something. + +## Database Naming + +Many database columns and JSON:API attributes have been renamed to conform to a [convention](/contributing.md#database). You will need to update any instances where your extension interacts with core data. You can see the changes in [#1344](https://github.com/flarum/core/pull/1344/files). + +## Extender + +Beta 8 introduces a new concept called **extenders** that replace the most common event listeners. You can learn more about how they work in the [updated extension docs](start.md#extenders). + +`bootstrap.php` has been renamed to `extend.php` and returns an array of extender instances and functions: + +```php +use Flarum\Extend; + +return [ + (new Extend\Frontend('forum')) + ->js(__DIR__.'/js/dist/forum.js') + ->css(__DIR__.'/less/forum.less') + ->route('/t/{slug}', 'tag') + ->route('/tags', 'tags'), + + function (Dispatcher $events) { + $events->subscribe(Listener\AddForumTagsRelationship::class); + } +] +``` + +If you're listening for any of the following events, you'll need to update your code to use an extender instead. See the relevant docs for more information. + +| Event | Extender | +| ------------------------------------- | --------------------------- | +| `Flarum\Event\ConfigureFormatter`* | `Flarum\Extend\Formatter` | +| `Flarum\Event\ConfigureWebApp`* | `Flarum\Extend\Frontend` | +| `Flarum\Event\ConfigureClientView`* | `Flarum\Extend\Frontend` | +| `Flarum\Event\ConfigureLocales` | `Flarum\Extend\Locales` | +| `Flarum\Event\ConfigureApiRoutes` | `Flarum\Extend\Routes` | +| `Flarum\Event\ConfigureForumRoutes` | `Flarum\Extend\Routes` | + +_\* class no longer exists_ + +## JavaScript Tooling + +Previously Flarum and its extensions used a custom Gulp workflow to compile ES6 source code into something that browsers could understand. Beta 8 switches to a more conventional approach with Webpack. + +You will need to tweak the structure of your extension's `js` directory. Currently, your JS file hierarchy looks something like the following: + +``` +js +├── admin +│ ├── src +│ │ └── main.js +│ ├── dist +│ │ └── extension.js +│ ├── Gulpfile.js +│ └── package.json +└── forum + ├── src + │ └── main.js + ├── dist + │ └── extension.js + ├── Gulpfile.js + └── package.json +``` + +You'll need to make the following changes: + +1. Update `package.json` and create `webpack.config.js`, `forum.js`, and `admin.js` files using [these templates](frontend.md#transpilation). + +2. Inside your `admin` and `forum` *folders*, delete `Gulpfile.js`, `package.json`, and `dist`. Then inside each `src` folder, rename `main.js` to `index.js`. Now move all of the `src` files outside of `src` folder and delete it. + +3. In the root `js` folder create a folder called `src` and move your `admin` and `forum` *folders* into it. + +4. While still in your root `js` folder, run `npm install` and then `npm run build` to build the new JS dist files. + +If everything went right, your folder structure should look something like this: + +``` +js +├── src +│ ├── admin +│ │ └── index.js +│ └── forum +│ └── index.js +├── dist +│ ├── admin.js +│ ├── admin.js.map +│ ├── forum.js +│ └── forum.js.map +├── admin.js +├── forum.js +├── package.json +└── webpack.config.js +``` + +Take a look at the [bundled extensions](https://github.com/flarum) for more examples. + +## Font Awesome Icons + +Beta 8 upgrades to Font Awesome 5, in which icon class names have changed. The `flarum/helpers/icon` helper now requires the **full Font Awesome icon class names** to be passed, eg. `fas fa-bolt`. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/views.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/views.md new file mode 100644 index 000000000..fc4a75a86 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extend/views.md @@ -0,0 +1,63 @@ +# Views and Blade + +Although the Flarum UI you know and love is powered by our [Mithril frontend](frontend), server-side generated templates are still used throughout Flarum. Most notably, the HTML skeleton of the forum, which includes various SEO meta tags, as well as the no-js view of the forum, is implemented through the Views and Blade systems. + +[Blade](https://laravel.com/docs/8.x/blade) is Laravel's templating engine, which allows you to conveniently generate HTML (or other static content) from PHP. It's the same idea as [Jinja](https://jinja.palletsprojects.com/en/3.0.x/) or [EJS](https://ejs.co/). [Views](https://laravel.com/docs/8.x/views) are Laravel's system for organizing/registering Blade templates, and also includes utilities for rendering them and providing them with variables. + +For our purposes, views are directories containing `.blade.php` template files (possibly contained in subdirectories). + +## Adding Views + +You will need to tell the view factory where it can find your extension's view files by adding a `View` extender to `extend.php`: + +```php +use Flarum\Extend; +use Illuminate\Contracts\View\Factory; + +return [ + (new Extend\View) + ->namespace('acme.hello-world', __DIR__.'/views'), +]; +``` + + +## Blade Templates + +To learn about the syntax for Blade templates, read [Laravel's documentation](https://laravel.com/docs/8.x/blade). + +Once you've set up your views, you can render them to strings: + +```php +// Here, $view is of type `Illuminate\Contracts\View\Factory` +$renderedString = $view->make('acme.hello-world::greeting')->render(); + +// You can also pass variables to the view: +$renderedString = $view->make('acme.hello-world::greeting', ['varName' => true])->render(); +``` + +You can obtain the view factory instance through dependency injection. + +The format is `"VIEW_NAMESPACE::VIEW_NAME"`. If the view folder is organized as subdirectories, replace `/` with `.` in the pack. So if you have a file at `"forum/error.blade.php"` in a namespace called `"custom-views"`, you would use `"custom-views::forum.error"`. + +Note that all Blade templates rendered this way automatically have access to the following variables: + +- `$url`: a [URL generator](routes#generating-urls) instance. +- `$translator`: a [Translator](i18n#server-side-translation) instance. +- `$settings`: a [SettingsInterface](settings) instance. +- `$slugManager`: a [SlugManager](slugging) instance. + +Additionally, templates used by [content logic](routes#content) have access to `$forum`, which represents the [Forum API Document's attributes](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Serializer/ForumSerializer.php#L19). + +## Overriding Views + +If you want to override templates added by core or extensions, set up a view folder structure matching the one you are trying to override, containing just the files you are trying to override. Then use the `View` extender's `extendNamespace` method: + +```php +use Flarum\Extend; +use Illuminate\Contracts\View\Factory; + +return [ + (new Extend\View) + ->extendNamespace('acme.hello-world', __DIR__.'/override_views'); +]; +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extenders.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extenders.md new file mode 100644 index 000000000..c680b9932 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extenders.md @@ -0,0 +1,23 @@ +# Local Extenders + +If there are customizations you want to make to your site without distributing an entire extension, you can do so by using **local extenders**. Each Flarum installation comes with an `extend.php` file where you can add extender instances, just like in a full extension. + +See our [extension documentation](extend/start.md) for more information about extenders (and even an [example of a local extender](extend/start.md#hello-world)). + +If you need to create new files (when adding a custom class to be imported for extenders), you'll need to adjust your composer.json a bit. Add the following: + +```json +"autoload": { + "psr-4": { + "App\\": "app/" + } +}, +``` + +Now you can create new PHP files in an `app` subdirectory using the `App\...` namespace. + +:::tip Local Extenders vs Extensions + +Local extenders can be good for small tweaks, but if you need large customizations, an extension might be a better choice: a separate codebase, cleaner handling of many files, developer tooling, and the ability to easily open source are big benefits. + +::: diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/extensions.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extensions.md new file mode 100644 index 000000000..36868caa1 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/extensions.md @@ -0,0 +1,118 @@ +# Estensioni + +Flarum è minimalista, ma è anche altamente estensibile. In effetti, la maggior parte delle funzionalità fornite con Flarum sono in realtà estensioni! + +Questo approccio rende Flarum estremamente personalizzabile: Puoi disabilitare tutte le funzionalità che non ti servono e installare altre estensioni per rendere il tuo forum perfetto per la tua comunità. + +Per ulteriori informazioni sulla filosofia di Flarum su quali funzionalità includiamo nel core o se stai cercando di creare la tua estensione, consulta la [documentazione estensioni](extend/README.md). Questo articolo si concentrerà sulla gestione delle estensioni dal punto di vista dell'amministratore del forum. + +## Extension Manager + +The extension manager is an extension that comes bundled with Flarum when installed via an archive. It provides a graphical interface for installing and updating both extensions and Flarum itself. + +If you do not have the extension manager installed and you wish to install it, you can do so by running the following command in your Flarum directory: + +```bash +composer require flarum/extension-manager:"*" +``` + +:::warning + +The extension manager allows an admin user to install any composer package. Only install the extension manager if you trust all of your forum admins with such permissions. + +::: + +![extension manager admin page](https://github.com/flarum/docs/assets/20267363/d0e1f7a5-e194-4acd-af63-7b8ddd95c26b) + + +## Trovare le estensioni + +Flarum ha un vasto ecosistema di estensioni, molte delle quali sono open source è grautie. Per trovare nuove e fantastiche estensioni, visita il tag [Estensioni](https://discuss.flarum.org/t/extensions) sul forum ufficiale di Flarum. Il non ufficiale [Database estensioni Extiverse](https://extiverse.com/) è anch'esso una valida alternativa. + +## Installare le estensioni + +### Through the interface + +Using the extension manager extension, you can install extensions directly from the admin dashboard. Once you have browsed the list of available extensions from the links above, and found one you want to install, you can install it by entering the extension's composer package name into the extension manager's installation input. + +![Installing an extension](/en/img/install-extension.png) + +### Through the command line + +Proprio come Flarum, le estensioni vengono installate tramite [Composer](https://getcomposer.org), usando SSH. Per installare un estensione: + +1. `cd` nella tua directory Flarum. `cd` fino alla cartella che contiene `composer.json`. Puoi controllare i contenuti della directory tramite `ls -la`. +2. Lancia `composer require COMPOSER_PACKAGE_NAME:*`. Questo solitamente compare nel post o nella documentazione dell'estensione. + +## Gestire le estensioni + +### Through the interface + +Using the extension manager extension, you can update extensions directly from the admin dashboard. You can run a check for updates by clicking the "Check for updates" button in the extension manager. If there are updates available, you can update all extensions by clicking the "Global update" button. Or, you can update individual extensions by clicking the "Update" button next to the extension you want to update. + +![Updating an extension](/en/img/update-extension.png) + +### Through the command line + +Seguire le istruzioni fornite dagli sviluppatori di estensioni. Se stai usando `*` come stringa di versione per le estensioni ([come raccomandato](composer.md)), eseguire i comandi elencati nella guida di aggiornamento di [Flarum](update.md) dovrebbe aggiornare tutte le estensioni. + +## Disinstallazione Delle Estensioni + +### Through the interface + +Using the extension manager extension, you can uninstall extensions directly from the admin dashboard. You can uninstall an extension by clicking the "Uninstall" button next to the extension you want to uninstall inside the extension's page. + +![Uninstalling an extension](/en/img/uninstall-extension.png) + +### Through the command line + +Analogamente all'installazione, per rimuovere un'estensione: + +0. If you want to remove all database tables created by the extension, click the "Purge" button in the admin dashboard. Per maggiori informazioni, vedere [qui sotto](#managing-extensions). +1. `cd` nella tua directory Flarum. +2. Lancia `composer require COMPOSER_PACKAGE_NAME`. Questo solitamente compare nel post o nella documentazione dell'estensione. + +## Gestire le estensioni + +Each individual extension page of the admin dashboard provides a convenient way to manage the extension. Potrai: + +- Enable or disable the extension. +- See the settings provided by the extension, and change them. +- Revert an extension's migrations to remove any database modifications it made (this can be done with the Purge button). Ciò rimuoverà TUTTI i dati associati all'estensione ed è irreversibile. Dovrebbe essere fatto solo quando rimuovi un'estensione e non prevedi di installarla di nuovo. È anche del tutto facoltativo. +- See the extension's README, if it has one. +- See the extension's version. +- Uninstall the extension if the extension manager is installed. + +## Configuring additional extension repository sources + +The extension manager uses `composer` under the hood, and as such, it looks for extension packages in the same places as `composer`. By default, this is [Packagist](https://packagist.org/). However, you can configure additional sources for the extension manager to look for extensions in. This is useful if you want to install an extension that is not available on Packagist. + +In the admin page of the extension manager, clicking the **Add Repository** button will open a modal where you can enter the name and URL of the repository you want to add. The name is just a label for the repository, and can be anything you want. The URL should be the URL of the repository which depends on the type of repository you want to add. + +### Adding a repository from a VCS + +If you want to add a repository from a VCS (e.g. GitHub, GitLab, BitBucket, etc), the URL should be the URL of the repository's VCS. For example, if you had a private GitHub repository at `https://github.com/acme/flarum-extension`, you would enter that URL into the URL field. If it is a private source, you will need to enter an authentication method through the **New authentication method** button. The token can be generated from your VCS provider's website, and the host should be the domain of the VCS provider (e.g. `github.com`). + +### Adding a composer repository + +Extiverse provides access to premium extensions. It is a good example of a composer repository. You would specify the URL as `https://flarum.org/composer/` and the name as `premium`. You would also need to enter an authentication method through the **New authentication method** button. The token can be generated from your Flarum account's [subscriptions](https://flarum.org/dashboard/subscriptions) page with the Instructions button. + +* Type: `HTTP Bearer` +* Host: `flarum.org` + +![Configure repositories](/en/img/config-repositories.png) + +:::info + +The configured repositories and auth methods will be active for both the command line and the admin dashboard. If you configure them from the command line however, you must not include the flag `--global`. + +::: + +## Installing Non-stable extensions + +If for whatever reason you want to install a non-stable extension (e.g. a beta, alpha or RC version) you must first update the **Minimum stability** setting to the wanted stability. + +* If you set it to Alpha, you will be able to install alpha, beta, RC (Release Candidate) and stable versions. +* If you set it to Beta, you will be able to install beta, RC and stable versions. +* If you set it to RC, you will be able to install RC and stable versions. +* If you set it to Stable, you will only be able to install stable versions. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/faq.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/faq.md new file mode 100644 index 000000000..5a166f573 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/faq.md @@ -0,0 +1,35 @@ +# FAQ + +### Flarum è stabile? + +Sì! Dopo 6 anni di sviluppo, Flarum 1.0.0 è finalmente arrivato. + +### Cosa succede dopo la versione stabile di Flarum? + +Stiamo ancora lavorando ad una roadmap formale. Abbiamo molti piani e idee e non vediamo l'ora di condividere un traguardo più approfondito con la community. + +### Posso donare denaro per accelerare lo sviluppo? + +Tutte le donazioni sono ben accette. Puoi effettuarle tramite [Github Sponsors](https://github.com/sponsors/flarum) o [OpenCollective](https://opencollective.com/flarum). + +Tuttavia, le donazioni non avranno un impatto diretto sulla velocità di sviluppo di Flarum. Incoraggiamo inoltre gli utenti a contribuire in altri modi, ad esempio [contribuire al codice](contributing.md), [creare estensioni](/extend/), scrivere documentazione, tradurre Flarum in altre lingue, fornire aiuto e supporto sul [forum](https://discuss.flarum.org/)... + +### Flarum avrà [nome feauture]? Quando? Perchè no? + +Al momento non è possibile, ma speriamo di lavorare su integrazioni come queste in futuro. + +### Perchè non è stato risolto ancora il [nome problema]? + +Anche in questo caso, la risposta è "prima le prime cose". Se non abbiamo ancora risolto un problema (o gli abbiamo assegnato un traguardo), è perché stiamo lavorando a qualcos'altro che è altrettanto importante. Per favore sii paziente; proveremo a farlo prima del rilascio. Oppure, se hai fretta, sentiti libero di aggiustarlo da solo e [contribuire al progetto](contributing.md)! + +### Perchè non è stato risolto ancora il [nome problema]? + +Attualmente non forniamo software di migrazione ufficiali, ma ci sono molte soluzioni della comunità già pronte all'uso. Una volta che siamo sicuri che Flarum è pronto per essere utilizzato in produzione, inizieremo a creare strumenti per importare dati da altri software per forum come esoTalk, FluxBB, phpBB, Discourse e altri. + +### Potrò migrare il mio forum su Flarum? + +> "Attraverso un'arcana e ardua prova, che coinvolge rituali mistici, pericolo di vita e avventure in terre lontane dove molti vanno e pochi tornano." ~ jordanjay29 + +La vera risposta è che generalmente teniamo d'occhio la nostra comunità per i membri eccezionali che potrebbero costituire un buon personale. Onestamente, per la maggior parte del nostro attuale staff, quello che hanno fatto prima di diventare parte del personale non era molto diverso da quello che fanno ora. + +Trova una passione e contribuisci come ritieni sia opportuno. Quindi lasciate che prenda il suo corso. Non devi avere un badge per essere rispettato qui. \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/install.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/install.md new file mode 100644 index 000000000..1f727ad95 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/install.md @@ -0,0 +1,198 @@ +# Installazione + +:::info Una veloce prova su strada? + +Fatti un giro sul nostro [forum di dimostrazione](https://discuss.flarum.org/d/21101) o sulla community verificata italiana [Flarum.it](https://flarum.it). Oppure crea il tuo forum in pochi secondi su [Free Flarum](https://www.freeflarum.com), un servizio gratuito non affiliato al team Flarum. + +::: + +## Requisiti del server + +Prima di installare Flarum, è importante verificare che il tuo server soddisfi i requisiti. Per eseguire Flarum, avrai bisogno di: + +* **Apache** (con mod\_rewrite abilitato) o **Nginx** +* **PHP 7.3+** with the following extensions: curl, dom, fileinfo, gd, json, mbstring, openssl, pdo\_mysql, tokenizer, zip +* **MySQL 5.6+** o **MariaDB 10.0.5+** +* **SSH (command-line) access** to run potentially necessary software maintenance commands, and Composer if you intend on using the command-line to install and manage Flarum extensions. + +## Installare Flarum + +### Installing by unpacking an archive + +If you don't have SSH access to your server or you prefer not to use the command line, you can install Flarum by unpacking an archive. Below is a list of the available archives, make sure you choose the one that matches your PHP version and public path or lack thereof preference. + +| Flarum Version | PHP Version | Public Path | Type | Archive | +| -------------- | ----------------- | ----------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1.x | 8.3 (recommended) | No | ZIP | [flarum-v1.x-no-public-dir-php8.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.3.zip) | +| 1.x | 8.3 (recommended) | Yes | TAR.GZ | [flarum-v1.x-php8.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.3.tar.gz) | +| 1.x | 8.3 (recommended) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.3.tar.gz) | +| 1.x | 8.3 (recommended) | Yes | ZIP | [flarum-v1.x-php8.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.3.zip) | +| 1.x | 8.2 (recommended) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.2.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.2.tar.gz) | +| 1.x | 8.2 (recommended) | Yes | TAR.GZ | [flarum-v1.x-php8.2.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.2.tar.gz) | +| 1.x | 8.2 (recommended) | No | ZIP | [flarum-v1.x-no-public-dir-php8.2.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.2.zip) | +| 1.x | 8.2 (recommended) | Yes | ZIP | [flarum-v1.x-php8.2.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.2.zip) | +| 1.x | 8.1 | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.1.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.1.tar.gz) | +| 1.x | 8.1 | Yes | TAR.GZ | [flarum-v1.x-php8.1.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.1.tar.gz) | +| 1.x | 8.1 | No | ZIP | [flarum-v1.x-no-public-dir-php8.1.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.1.zip) | +| 1.x | 8.1 | Yes | ZIP | [flarum-v1.x-php8.1.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.1.zip) | +| 1.x | 8.0 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.0.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.0.tar.gz) | +| 1.x | 8.0 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php8.0.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.0.tar.gz) | +| 1.x | 8.0 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php8.0.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.0.zip) | +| 1.x | 8.0 (end of life) | Yes | ZIP | [flarum-v1.x-php8.0.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.0.zip) | +| 1.x | 7.4 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php7.4.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.4.tar.gz) | +| 1.x | 7.4 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php7.4.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.4.tar.gz) | +| 1.x | 7.4 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php7.4.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.4.zip) | +| 1.x | 7.4 (end of life) | Yes | ZIP | [flarum-v1.x-php7.4.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.4.zip) | +| 1.x | 7.3 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php7.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.3.tar.gz) | +| 1.x | 7.3 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php7.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.3.tar.gz) | +| 1.x | 7.3 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php7.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.3.zip) | +| 1.x | 7.3 (end of life) | Yes | ZIP | [flarum-v1.x-php7.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.3.zip) | + +### Installing using the Command Line Interface + +Flarum usa [Composer](https://getcomposer.org) per gestire le sue dipendenze ed estensioni. Prima di installare Flarum, sar� necessario [installare Composer](https://getcomposer.org) sulla tua macchina. Successivamente, esegui questo comando in una cartella vuota in cui desideri installare Flarum: + +```bash +compositore create-project flarum/flarum . +``` + +Mentre questo comando è in esecuzione, puoi configurare il tuo server web. Dovrai assicurarti che il tuo webroot sia impostato su `/percorso/del/tuo/forum/public`, e impostare [URL Rewriting](#url-rewriting) come descritto qui sotto. + +Quando tutto è pronto, accedi al tuo forum in un browser web e segui le istruzioni a video per completare l'installazione + +If you wish to install and update extensions from the admin dashboard, you need to also install the [Extension Manager](extensions.md) extension. + +```bash +composer require flarum/extension-manager:* +``` + +:::warning + +The extension manager allows an admin user to install any composer package. Only install the extension manager if you trust all of your forum admins with such permissions. + +::: + +## Riscrittura URL + +### Apache + +Flarum include un file `.htaccess` nella cartella `public` – assicurati che sia stato caricato correttamente. **Flarum non funzionerà correttamente se `mod_rewrite` non è abilitato o il file `.htaccess` non è accessibile.** Assicurati di verificare con il tuo provider di hosting (o il tuo VPS) che queste funzionalità siano abilitate. Se gestisci il tuo server, potresti dover aggiungere quanto segue alla configurazione del tuo sito per abilitare i file `.htaccess`. + +``` + + AllowOverride All + +``` + +Ciò garantisce che gli override di htaccess siano consentiti in modo che Flarum possa riscrivere correttamente gli URL. + +I metodi per abilitare `mod_rewrite` dipendono dal tuo OS. Puoi abilitarli eseguendo `sudo a2enmod rewrite` su Ubuntu. `mod_rewrite` è abilitato di default su CentOS. Non dimenticare di riavviare Apache dopo aver apportato modifiche! + +### Nginx + +Flarum include il file `.nginx.conf` – assicurati che sia caricato correttamente. Quindi, supponendo che tu abbia un sito PHP impostato all'interno di Nginx, aggiungi quanto segue al blocco di configurazione del tuo server: + +```nginx +include /path/to/flarum/.nginx.conf; +``` + +### Caddy + +Caddy richiede una configurazione molto semplice affinché Flarum funzioni correttamente. Nota che devi sostituire l'URL con il tuo URL e il percorso con il tuo percorso della cartella `public`. Se stai usando una versione diversa di PHP, dovrai anche cambiare il percorso del file `fastcgi` per puntare al socket o all'URL di installazione PHP corretto. + +``` +www.example.com { + root * /var/www/flarum/public + php_fastcgi unix//var/run/php/php7.4-fpm.sock + header /assets/* { + +Cache-Control "public, must-revalidate, proxy-revalidate" + +Cache-Control "max-age=25000" + Pragma "public" + } + file_server +} +``` +## Proprietà della cartella + +Durante l'installazione, Flarum potrebbe richiedere di rendere scrivibili alcune directory. Modern operating systems are generally multi-user, meaning that the user you log in as is not the same as the user Flarum is running as. The user that Flarum is running as MUST have read + write access to: + +- The root install directory, so Flarum can edit `config.php`. +- The `storage` subdirectory, so Flarum can edit logs and store cached data. +- The `assets` subdirectory, so that logos and avatars can be uploaded to the filesystem. + +Extensions might require other directories, so you might want to recursively grant write access to the entire Flarum root install directory. + +There are several commands you'll need to run in order to set up file permissions. Please note that if your install doesn't show warnings after executing just some of these, you don't need to run the rest. + +First, you'll need to allow write access to the directory. On Linux: + +```bash +chmod 775 -R /path/to/directory +``` + +If that isn't enough, you may need to check that your files are owned by the correct group and user. By default, in most Linux distributions `www-data` is the group and user that both PHP and the web server operate under. You'll need to look into the specifics of your distro and web server setup to make sure. You can change the folder ownership in most Linux operating systems by running: + +```bash +chown -R www-data:www-data /path/to/directory +``` + +With `www-data` changed to something else if a different user/group is used for your web server. + +Additionally, you'll need to ensure that your CLI user (the one you're logged into the terminal as) has ownership, so that you can install extensions and manage the Flarum installation via CLI. To do this, add your current user (`whoami`) to the web server group (usually `www-data`) via `usermod -a -G www-data YOUR_USERNAME`. You will likely need to log out and back in for this change to take effect. + +Finally, if that doesn't work, you might need to configure [SELinux](https://www.redhat.com/en/topics/linux/what-is-selinux) to allow the web server to write to the directory. To do so, run: + +```bash +chcon -R -t httpd_sys_rw_content_t /path/to/directory +``` + +To find out more about these commands as well as file permissions and ownership on Linux, read [this tutorial](https://www.thegeekdiary.com/understanding-basic-file-permissions-and-ownership-in-linux/). If you are setting up Flarum on Windows, you may find the answers to [this Super User question](https://superuser.com/questions/106181/equivalent-of-chmod-to-change-file-permissions-in-windows) useful. + +:::caution Environments may vary + +Your environment may vary from the documentation provided, please consult your web server configuration or web hosting provider for the proper user and group that PHP and the web server operate under. + +::: + +:::danger Never use permission 777 + +You should never set any folder or file to permission level `777`, as this permission level allows anyone to access the content of the folder and file regardless of user or group. + +::: + +## Personalizzare i percorsi + +By default Flarum's directory structure includes a `public` directory which contains only publicly-accessible files. This is a security best-practice, ensuring that all sensitive source code files are completely inaccessible from the web root. + +However, if you wish to host Flarum in a subdirectory (like `yoursite.com/forum`), or if your host doesn't give you control over your webroot (you're stuck with something like `public_html` or `htdocs`), you can set up Flarum without the `public` directory. + +If you intend to install Flarum using one of the archives, you can simply use the `no-public-dir` (Public Path = No) [archives](#installing-by-unpacking-an-archive) and skip the rest of this section. If you're installing via Composer, you'll need to follow the instructions below. + +Simply move all the files inside the `public` directory (including `.htaccess`) into the directory you want to serve Flarum from. Then edit `.htaccess` and uncomment lines 9-15 in order to protect sensitive resources. For Nginx, uncomment lines 8-11 of `.nginx.conf`. + +You will also need to edit the `index.php` file and change the following line: + +```php +$site = require './site.php'; +``` + + Edit the `site.php` and update the paths in the following lines to reflect your new directory structure: + +```php +'base' => __DIR__, +'public' => __DIR__, +'storage' => __DIR__.'/storage', +``` + +Finally, check `config.php` and make sure the `url` value is correct. + +## Importazione dati da altro forum + +If you have an existing community and don't want to start from scratch, you may be able to import your existing data into Flarum. While there are no official importers yet, the community has made several unofficial importers: + +* [FluxBB](https://discuss.flarum.org/d/3867-fluxbb-to-flarum-migration-tool) +* [MyBB](https://discuss.flarum.org/d/5506-mybb-migrate-script) +* [phpBB](https://discuss.flarum.org/d/1117-phpbb-migrate-script-updated-for-beta-5) +* [SMF2](https://github.com/ItalianSpaceAstronauticsAssociation/smf2_to_flarum) + +These can be used for other forum software as well by migrating to phpBB first, then to Flarum. Be aware that we can't guarantee that these will work nor can we offer support for them. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/README.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/README.md new file mode 100644 index 000000000..ff153a3bc --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/README.md @@ -0,0 +1,7 @@ +--- +slug: '/internal' +--- + +# Internal Team Docs + +This is a new documentation section, where we will be posting some docs used internally by the Flarum team. We are starting this section to provide our community with transparency as to how Flarum is run, and to help those hoping to contribute to Flarum. \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md new file mode 100644 index 000000000..555e7977c --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md @@ -0,0 +1,28 @@ +# Bundled Extensions Policy + +This document is to assist in deciding what core features should be bundled or maintained by the Flarum project team. + +Understand that Flarum aims to have a lean and efficient team. To guarantee a transparent workload, we intentionally have a "this could be an extension" mentality. The acronym D.O.R.C. spells out our decision-making process. + +- **Density**: prevent bloating Flarum so that it becomes a burden to install on shared hosting plans with limited space. +- **Opinionatedness**: no extensions should be bundled that is only useful by only a limited amount of communities or on specific hosting environments. +- **Responsibility**: extensions that could easily be maintained by others should be maintained by others. +- **Complexity**: extensions that are complex in terms of design, frontend or backend code should not be a responsibility of the Flarum project team. + +### Density + +To prevent the installation size of Flarum from continuously increasing we need to protect it from extensions that bloat it. We should ship extensions with Flarum that, for instance, have kilobytes in media files. + +### Opinionatedness + +Our goal is to allow installation of Flarum, in its vanilla form, by any community on any hosting environment. This includes shared hosting environment as well. + +Releasing Flarum with extensions that add functionality specific to cloud based (AWS) installations or for corporate support communities, as such, is unwanted. + +### Responsibility + +Protecting the time of the project team is key. To do so we should empower the ecosystem in building extensions that it needs. Therefor we distance ourselves from the responsibility of building every and all extensions. The responsibility of extension development is held primarily by our community. + +### Complexity + +Complex extensions require a vast amount of time, not just for development, but also documentation and support. To protect the lean and efficient principles of the team, we will not take ownership of extensions that add this complexity. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md new file mode 100644 index 000000000..c6ef1c890 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md @@ -0,0 +1,87 @@ +# Extension Manager +This contains an explanation of how the extension manager works and what it has to offer. + +slightly outdated: see [the extensions guide for more](/extensions.md). + +## Contents +* Installing, Updating, and Removing Extensions. +* [Checking for Updates](#checking-for-updates). +* [Global Flarum Update](#global-flarum-updates). +* [Patch-Minor Flarum Updates](#patch-minor-flarum-updates). +* [Major Flarum Update](#major-flarum-updates). +* [Flarum Updates (global, minor, major)](#flarum-updates-global-minor-major). +* [Background Tasks](#background-tasks). + +## Requirements +There are some obstacles that need to be taken care of before this can be used. + +### File Permissions +The relevant machine web user needs to have permissions to read and write to: `vendor`, `composer.json`, `composer.lock` and `storage`. Right now a warning shows up when this is not the case, this should preferably be changed to mention only the files/dirs where permissions are lacking instead of all of them. + +![flarum lan_admin (3)](https://user-images.githubusercontent.com/20267363/135268536-f79d42ab-6e05-4e41-b2ab-d95ec7a8b021.png) + +### Path Repository +In development environments (and production in rare scenarios) there should a path repository to a directory containing (mostly dev) packages, the path to this directory must be changed to an absolute path otherwise composer will have trouble running any command. Additionally the path repository by default has higher priority, so requiring an extension that exists in that repository will probably fail, unless a `*@dev` constraint is specified, in which case the extension manager should not be used for dev purposes anyway. + +There is currently now hint of any of this in the extension manager UI. + +## Common Actions +Each one of the features listed above is basically a composer command or two, and there are common actions/common behaviour between them all. + +* Restricting access to the admin. +* Validating the provided package name or the extension id if given. +* Erroring out if installing an existing extension, updating or removing a non existing extension ...etc +* Running the command. This [auto logs the output](#command-output-logging). +* [Erroring out on command failure](#command-failure). +* Dispatching an event. +* If running an update: + + Clear Cache. + + Run Migrations. + + Publish Assets. + + Run an update check, and log any extensions that didn't update to their latest versions in the update process. + +### Command Output Logging +Considering this is still experimental and especially for the sake of easier support, each command output is logged to `storage/logs/composer` just like the flarum error logs, allowing to go back and see what happened during a command execution. + +### Command Failure +When a composer command fails (recognised by the exit code), an exception is thrown containing a reason guessed by the exception based on the command output text. Guessed causes render into proper explanatory alert messages on the frontend. + +## Checking for Updates +This executes the command `composer outdated -D --format json` which checks for updates of packages directly required in the root `composer.json` and outputs the results in JSON format. Only packages marked as `semver-safe-update` and `update-possible` by composer are displayed. + +The information about the last update check is saved into a JSON setting. + +![flarum lan_admin (4)](https://user-images.githubusercontent.com/20267363/135272032-9de37599-b364-4e42-b234-1113135eaa83.png) + +## Global Flarum Updates +Simply runs the command `command update --prefer-dist --no-dev -a --with-all-dependencies`, useful for updating all packages. + +## Patch-Minor Flarum Updates +This changes directly required package versions to `*` and then executes the command `command update --prefer-dist --no-dev -a --with-all-dependencies`. + +![flarum lan_admin (5)](https://user-images.githubusercontent.com/20267363/135276114-ae438c2f-4122-45bd-b32f-690de3b56e25.png) + +## Major Flarum Updates +This changes directly required package versions to `*`, changes core to the latest major version requirement and then executes the same command above. Upon failure, it can be correctly guessed that some extensions are not compatible with the new major version, the exception details will include an array of extension package names that are not compatible, and it'll be rendered in the frontend, with the ability to run a `composer why-not flarum/core 2.0` for more details. + +![major update UI](https://user-images.githubusercontent.com/20267363/143277865-8323fa9a-c80f-4015-baca-fce4d2b5d585.png) + +## Flarum Updates (global, minor, major) +Information about the last updates ran are saved in a `last_update_run` JSON setting, which can contain an array of extension package names that didn't update to their latest version in the process, this is rendered in the frontend as warning icon buttons on the extension items, clicking on them will execute a `composer why-not`, displaying the details of the failure in a modal. + +![UI with list of extensions containing warning icon buttons](https://user-images.githubusercontent.com/20267363/143278774-6fada0da-dead-474b-8dfa-feda5021134f.png) ![UI with the modal showing the details](https://user-images.githubusercontent.com/20267363/143278786-d283db62-de96-4019-954e-932d0d6eac15.png) + +## Background Tasks +To get around timeout issues, composer commands can also run on the background use the queue. Users can be pointed towards [Blomstra's Database Queue Implementation](https://discuss.flarum.org/d/28151-database-queue-the-simplest-queue-even-for-shared-hosting) as a basic queue solution. It contains instructions on how to enable the queue through a cron job. + +:::danger Cron Job PHP Process Version + +It is common for shared hosts to have a low php version used in SSH, users must be pointed to the fact that they have to make sure the php process is of a version compatible with Flarum. Either by manually checking or by asking their hosts. + +::: + +![Extension Manager Queue Table Preview](/en/img/extension-manager-queue.png) + +## TODO +- Try on shared hosting. +- Better explanation on the UI about background tasks. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md new file mode 100644 index 000000000..067e2809f --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md @@ -0,0 +1,38 @@ +# PR Merging Policy + +Technical contributions to the Flarum source code go through a review process. Over the years we have tuned this process based on our experiences, our targeted development speed and availability. + +## What makes a great Pull Request? + +Great pull requests: + +- Have the [Pull Request template](https://github.com/flarum/.github/blob/main/PULL_REQUEST_TEMPLATE.md) filled out completely when opening a pull request. +- Do not combine different changes. Although tempting, don't change formatting of unrelated code. Stick to the one feature or change you wish to contribute. +- Have a related issue where the technical implementation has been agreed upon by the core team, or has been approved on by the core team through discussion on the official forums or other channels like Discord. +- Clearly explain the need for the change and list the areas where the pull request requires discussion. + +## Implementation Review Criteria + +- Adheres to our conventions or can be patched up easily after merging, follows proper code style. +- Are there any implementation details that could be done better through alternate technologies/technical approaches? +- Does not touch any lines outside of the intended changes, eg through formatting or compilation. +- If the changes are to code intended as a public API, has a proper doc block been included? + +## Merge Time! + +If all the checks in the template are met, **any** core developer may merge this PR. If the PR is authored by a core developer, they should probably be the ones to merge it. + +- Merging: + - GitHub offers several ways to merge a PR. Choose between the following strategies: + - **Merge** when the PR branch consists of atomic, well-described commits that are nice to have in the version history. + - **Squash** when lots of cleanup commits have accumulated. Please make sure to follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) spec for the squash commit. We usually find several commits from bots like StyleCI in these prefabricated commit messages, their commit messages should be removed. + +- After merging: + - Assign the related issue (if none exists, the pull request itself, but never both) to the appropriate milestone. + - Close all relevant issues (*if* they are closed completely). + - Regressions should be labeled as such and removed from the project board and milestone after merging. + - Check for follow-up tasks: + - Merge related PRs (language files, extensions, documentations). + - Documentation updates. + - Create issues for further follow-up tasks, if necessary. + diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/merging.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/merging.md new file mode 100644 index 000000000..0408b1bee --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/merging.md @@ -0,0 +1,29 @@ +# PR Merging Workflow + + +## Implementation Review Criteria + +- Adheres to our conventions or can be patched up easily after merging, follows proper code style. +- Are there any implementation details that could be done better through alternate technologies/technical approaches? +- Does not touch any lines outside of the intended changes, eg through formatting or compilation. +- If the changes are to code intended as a public API, has a proper doc block been included? + +## Merge Time! + +If all of the checks in the template are met, **any** core developer may merge this PR. If the PR is authored by a core developer, they should probably be the ones to merge it. + +- Merging: + - GitHub offers several ways to merge a PR. Choose between the following strategies: + - **Merge** when the PR branch consists of atomic, well-described commits that are nice to have in the version history. + - **Squash** when lots of cleanup commits have accumulated. Please make sure to follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) spec for the squash commit. + +- After merging: + - Make sure the *issue* (if none exists, the PR - but not both) belongs to the appropriate milestone and project board. + - PRs in extensions cannot be assigned to core milestones, so create a core issue that references it and add it to the milestone. + - Close all relevant issues (*if* they are closed completely). + - Regressions should be labeled as such and removed from the project board and milestone after merging. + - Check for follow-up tasks: + - Merge related PRs (language files, extensions, documentations). + - Documentation updates. + - Create issues for further follow-up tasks, if necessary. + diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md new file mode 100644 index 000000000..823599db5 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md @@ -0,0 +1,89 @@ +# Package Manager +This contains an explanation of how the package manager works and what it has to offer. + +## Contents +* Installing, Updating, and Removing Extensions. +* [Checking for Updates](#checking-for-updates). +* [Global Flarum Update](#global-flarum-updates). +* [Patch-Minor Flarum Updates](#patch-minor-flarum-updates). +* [Major Flarum Update](#major-flarum-updates). +* [Flarum Updates (global, minor, major)](#flarum-updates-global-minor-major). +* [Background Tasks](#background-tasks). + +## Requirements +There are some obstacles that need to be taken care of before this can be used. + +### File Permissions +The relevant machine web user needs to have permissions to read and write to: `vendor`, `composer.json`, `composer.lock` and `storage`. Right now a warning shows up when this is not the case, this should preferably be changed to mention only the files/dirs where permissions are lacking instead of all of them. + +![flarum lan_admin (3)](https://user-images.githubusercontent.com/20267363/135268536-f79d42ab-6e05-4e41-b2ab-d95ec7a8b021.png) + +### Path Repository +In development environments (and production in rare scenarios) there should a path repository to a directory containing (mostly dev) packages, the path to this directory must be changed to an absolute path otherwise composer will have trouble running any command. Additionally the path repository by default has higher priority, so requiring an extension that exists in that repository will probably fail, unless a `*@dev` constraint is specified, in which case the package manager should not be used for dev purposes anyway. + +There is currently now hint of any of this in the package manager UI. + +## Common Actions +Each one of the features listed above is basically a composer command or two, and there are common actions/common behaviour between them all. + +* Restricting access to the admin. +* Validating the provided package name or the extension id if given. +* Erroring out if installing an existing extension, updating or removing a non existing extension ...etc +* Running the command. This [auto logs the output](#command-output-logging). +* [Erroring out on command failure](#command-failure). +* Dispatching an event. +* If running an update: + + Clear Cache. + + Run Migrations. + + Publish Assets. + + Run an update check, and log any extensions that didn't update to their latest versions in the update process. + +### Command Output Logging +Considering this is still experimental and especially for the sake of easier support, each command output is logged to `storage/logs/composer` just like the flarum error logs, allowing to go back and see what happened during a command execution. + +### Command Failure +When a composer command fails (recognised by the exit code), an exception is thrown containing a reason guessed by the exception based on the command output text. Guessed causes render into proper explanatory alert messages on the frontend. + +## Checking for Updates +This executes the command `composer outdated -D --format json` which checks for updates of packages directly required in the root `composer.json` and outputs the results in JSON format. Only packages marked as `semver-safe-update` and `update-possible` by composer are displayed. + +The information about the last update check is saved into a JSON setting. + +![flarum lan_admin (4)](https://user-images.githubusercontent.com/20267363/135272032-9de37599-b364-4e42-b234-1113135eaa83.png) + +## Global Flarum Updates +Simply runs the command `command update --prefer-dist --no-dev -a --with-all-dependencies`, useful for updating all packages. + +## Patch-Minor Flarum Updates +This changes directly required package versions to `*` and then executes the command `command update --prefer-dist --no-dev -a --with-all-dependencies`. + +![flarum lan_admin (5)](https://user-images.githubusercontent.com/20267363/135276114-ae438c2f-4122-45bd-b32f-690de3b56e25.png) + +## Major Flarum Updates +This changes directly required package versions to `*`, changes core to the latest major version requirement and then executes the same command above. Upon failure, it can be correctly guessed that some extensions are not compatible with the new major version, the exception details will include an array of extension package names that are not compatible, and it'll be rendered in the frontend, with the ability to run a `composer why-not flarum/core 2.0` for more details. + +![major update UI](https://user-images.githubusercontent.com/20267363/143277865-8323fa9a-c80f-4015-baca-fce4d2b5d585.png) + +## Flarum Updates (global, minor, major) +Information about the last updates ran are saved in a `last_update_run` JSON setting, which can contain an array of extension package names that didn't update to their latest version in the process, this is rendered in the frontend as warning icon buttons on the extension items, clicking on them will execute a `composer why-not`, displaying the details of the failure in a modal. + +![UI with list of extensions containing warning icon buttons](https://user-images.githubusercontent.com/20267363/143278774-6fada0da-dead-474b-8dfa-feda5021134f.png) ![UI with the modal showing the details](https://user-images.githubusercontent.com/20267363/143278786-d283db62-de96-4019-954e-932d0d6eac15.png) + +## Background Tasks +To get around timeout issues, composer commands can also run on the background use the queue. Users can be pointed towards [Blomstra's Database Queue Implementation](https://discuss.flarum.org/d/28151-database-queue-the-simplest-queue-even-for-shared-hosting) as a basic queue solution. It contains instructions on how to enable the queue through a cron job. + +:::danger Cron Job PHP Process Version + +It is common for shared hosts to have a low php version used in SSH, users must be pointed to the fact that they have to make sure the php process is of a version compatible with Flarum. Either by manually checking or by asking their hosts. + +::: + +![Package Manager Queue Table Preview](/en/img/package-manager-queue.png) + +## TODO +- Try on shared hosting. +- Composer command job must not overlap. +- Code TODOs. +- Better explanation on the UI about background tasks. +- Take into consideration a scenario where we're updating an extension that isn't a root required dependency, like bundles. +- Run one background task at a time, prevent user from triggering multiple tasks. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/languages.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/languages.md new file mode 100644 index 000000000..cd0fcb21a --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/languages.md @@ -0,0 +1,29 @@ +# Lingue + +È facile aggiungere una nuova lingua all'installazione di base di Flarum. Segui le istruzioni seguenti per scaricare e installare il language pack di tua scelta. + +Dopo aver aggiunto un language pack, puoi [impostarlo come lingua principale](#setting-the-default-language) del tuo forum.E se ti accorgi di non aver bisogno di uno dei tuoi language pack installati, puoi sempre [disabilitarlo](#disabling-a-language-pack). E se non hai mai bisogno di uno dei language pack installati, puoi sempre [disattivarlo](#disabling-a-language-pack). Se stai utilizzando estensioni di terze parti, assicurati di [leggere qui](#third-party-extensions) prima di iniziare. + +## Installazione language pack + +Per iniziare, visita il tag [Extensions > Languages](https://discuss.flarum.org/t/languages) nella community di FLarum, e carca il language pack che vuoi installare. + +I language pack vengono installati con lo stesso metodo utilizzato per le [estensioni](extensions.md). La lingua verrà visualizzata nella pagina Estensioni dell'interfaccia di amministrazione e potrai attivarla da lì. + +Questo è tutto quelo che devi fare! Ora dovresti essere in grado di utilizzare il selettore della lingua nell'intestazione del tuo sito per cambiare la visualizzazione del forum nella nuova lingua. + +## Impostare lingua di default + +Dopo aver installato un language pack e verificato che funzioni, potresti volerlo impostare come lingua predefinita per i nuovi utenti e ospiti. Potrai farlo nel pannello amministrazione sotto la voce **Impostazioni di Base**. + +## Disabilitare un Language Pack + +Se decidi di non aver bisogno di una determinata lingua, dopotutto, puoi disattivarla. Individua semplicemente il language pack fra le tue **Estensioni** nel pannello di amministrazione, e disabilitala. + +La disattivazione di una lingua può essere utile se gestisci un sito monolingue e non desideri che il selettore della lingua venga visualizzato nell'intestazione del sito. Il selettore della lingua è nascosto quando è abilitata una sola lingua. + +## Estensioni della community + +Sebbene i language pack scaricati dal sito della community di Flarum includano generalmente traduzioni per tutte le estensioni fornite in bundle con Flarum, di regola non saranno tradotte le estensioni di terze parti che potresti aver installato. Spetta agli sviluppatori fornire e mantenere le traduzioni per le loro estensioni. + +Pertanto, prima di installare un'estensione della community, è necessario verificare che includa le traduzioni nella lingua di tuo interesse. Se scopri che un'estensione non supporta una lingua di cui hai bisogno, contatta direttamente lo sviluppatore e fai in modo che vengano aggiunte le traduzioni necessarie, o utilizza un estensione per tradurle tu stesso. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/mail.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/mail.md new file mode 100644 index 000000000..9fd59c479 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/mail.md @@ -0,0 +1,29 @@ +# Configurazione Email + +Qualsiasi comunità necessita di inviare e-mail per consentire la verifica, reimpostazioni della password, notifiche e altre comunicazioni agli utenti. Configurare il tuo forum per l'invio di email dovrebbe essere uno dei tuoi primi passi come amministratore: una configurazione errata causerà errori quando gli utenti tenteranno di registrarsi. + +## Driver disponibili + +Flarum fornisce diversi driver di default, e sono elencati e spiegati di seguito. Gli sviluppatori inoltre possono anche aggiungere [driver personalizzati tramite estensioni](extend/mail.md). + +### SMTP + +Questo è probabilmente il driver di posta elettronica più comunemente utilizzato, che consente di configurare un host, una porta / crittografia, un nome utente e una password per un servizio SMTP esterno. Nel campo crittografia sarà possibile utilizzare solamente `ssl` o `tls`. + +### Mail + +Il driver `mail` proverà a utilizzare il sistema di posta sendmail / postfix incluso in molti server di hosting. Devi installare e configurare correttamente sendmail sul tuo server affinché funzioni. + +### Mailgun + +Questo driver utilizza il tuo account [Mailgun](https://www.mailgun.com/) per inviare email. Avrai bisogno di una chiave segreta, così come il dominio e la regione reperibili dalla configurazione della tua mailgun. + +Per utilizzare il driver mailgun, è necessario installare il pacchetto Guzzle (un client HTTP PHP). Puoi farlo eseguendo `composer require guzzlehttp/guzzle:^6.0|^7.0` nella tua directory principale di Flarum. + +### Log + +Il driver Log NON INVIA EMAIL,ed è utilizzato principalmente dagli sviluppatori. Scrive il contenuto di qualsiasi messaggio di posta elettronica nel file di registro in `DIRECTORY_PRINCIPALE_FLARUM/storage/logs`. + +## Email di prova + +Dopo aver salvato una configurazione di posta elettronica, è possibile fare clic sul pulsante "Invia mail di prova" nella pagina Posta del pannello di amministratore per assicurarti che la tua configurazione funzioni. Se visualizzi un errore o non ricevi un'email, modifica la configurazione e riprova. Assicurati di controllare lo spam se non ci sono errori e se non viene visualizzato nulla nella tua posta in arrivo. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/releases.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/releases.md new file mode 100644 index 000000000..7c007fcc7 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/releases.md @@ -0,0 +1,15 @@ +# Note di rilascio + + + + +Le note di rilascio possono essere trovate facilmente nel [Forum di Flarum](https://discuss.flarum.org/t/blog?sort=newest). diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/rest-api.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/rest-api.md new file mode 100644 index 000000000..7e91238d3 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/rest-api.md @@ -0,0 +1,375 @@ +# Consuming the REST API + +Flarum exposes a REST API which is used by the single page application but also available for external scripts. + +The API follows the best practices defined by the [JSON:API](https://jsonapi.org/) specification. + +:::info + +To extend the REST API with new endpoints, see [API and Data Flow](extend/api.md) in the developer documentation. + +::: + +## Authentication + +The single page app uses session cookies to authenticate against the API. External scripts can use stateless authentication using [API Keys](#api-keys) or [Access Tokens](#access-tokens). + +`GET` endpoints can be used without authentication. Only content visible to guests will be returned. Other endpoints generally cannot be used without authentication because of the [CSRF protection](#csrf-protection). + +### API keys + +API Keys are the primary way for scripts, tools and integrations to interact with Flarum. + +#### Creation + +There is currently no UI to manage API Keys, but they can be created manually in the `api_keys` table of the database. + +The following attributes can be filled: + +- `key`: Generate a long unique token (recommended: alpha-numerical, 40 characters) and set it here, this will be the token used in the `Authorization` header. +- `user_id`: Optional. If set, the key can only be used to act as the given user. + +The remaining attributes are either automatically filled or currently not used: + +- `id`: Will be filled by MySQL auto-increment. +- `allowed_ips`: Not implemented. +- `scopes`: Not implemented. +- `created_at`: Can be set to any date, but is meant for the date of creation of the key. +- `last_activity_at`: Will be updated automatically when the token is used. + +#### Usage + +Attach your key value to each API request using the `Authorization` header. Then provide the user ID you want to interact as at the end of the header: + + Authorization: Token YOUR_API_KEY_VALUE; userId=1 + +If a `user_id` value has been set for the key in the database, `userId=` will be ignored. Otherwise, it can be set to any valid user ID that exists in the database. + +### Access Tokens + +Access Tokens are short-lived tokens that belong to a specific user. + +Those tokens are used behind the scenes for cookie sessions. Their use in stateless API requests has the same effect as a regular session. The user last activity will be updated each time the token is used. + +#### Creation + +All users are allowed to create access tokens. To create a token, use the `/api/token` endpoint with the credentials of your user: + +``` +POST /api/token HTTP/1.1 + +{ + "identification": "Toby", + "password": "pass7word" +} + +HTTP/1.1 200 OK + +{ + "token": "YACub2KLfe8mfmHPcUKtt6t2SMJOGPXnZbqhc3nX", + "userId": "1" +} +``` + +At the moment, 3 token types exist, although only 2 types can be created via the REST API. + +- `session` tokens expire after 1h of inactivity. This is the default token type. +- `session_remember` tokens expire after 5 years of inactivity. They can be obtained by specifying `remember=1` in the request attributes. +- `developer` tokens never expire. They can only be created manually in the database at the moment. + +**All access tokens are deleted when the user logs out** (this includes `developer` tokens, although it is planned to change it). + +#### Usage + +Attach the returned `token` value to each API request using the `Authorization` header: + + Authorization: Token YACub2KLfe8mfmHPcUKtt6t2SMJOGPXnZbqhc3nX + +### CSRF Protection + +Most of the `POST`/`PUT`/`DELETE` API endpoints are protected against [Cross-site request forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery). This means stateless requests are not possible without authentication. + +When using an API Key or Access Token, CSRF protection is bypassed. + +## Endpoints + +This part of the documentation is still in progress. We are researching options to provide an automated documentation of the endpoints. + +Every extension adds new endpoints and attributes so it's difficult to provide a complete documentation of all endpoints. A good way to discover endpoints is to use the browser development tools to inspect requests made by the single page application. + +Below are a few examples of commonly used endpoints. JSON has been truncated to make reading easier. + +### List discussions + + GET /api/discussions + +```json +{ + "links": { + "first": "https://flarum.tld/api/discussions", + "next": "https://flarum.tld/api/discussions?page%5Boffset%5D=20" + }, + "data": [ + { + "type": "discussions", + "id": "234", + "attributes": { + "title": "Lorem Ipsum", + "slug": "234-lorem-ipsum", + "commentCount": 10, + "participantCount": 3, + "createdAt": "2022-01-01T10:20:30+00:00", + "lastPostedAt": "2022-01-05T10:20:30+00:00", + "lastPostNumber": 10, + "canReply": true, + "canRename": true, + "canDelete": true, + "canHide": true, + "isHidden": true, + "hiddenAt": "2022-01-06T10:20:30+00:00", + "lastReadAt": "2022-01-02T10:20:30+00:00", + "lastReadPostNumber": 2, + "isApproved": true, + "canTag": true, + "isLocked": false, + "canLock": true, + "isSticky": false, + "canSticky": true, + "canMerge": true, + "subscription": null + }, + "relationships": { + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + "lastPostedUser": { + "data": { + "type": "users", + "id": "64" + } + }, + "tags": { + "data": [ + { + "type": "tags", + "id": "3" + } + ] + }, + "firstPost": { + "data": { + "type": "posts", + "id": "668" + } + } + } + }, + { + "type": "discussions", + "id": "234", + "attributes": { + // [...] + }, + "relationships": { + // [...] + } + }, + // [...] more discussions + ], + "included": [ + { + "type": "users", + "id": "1", + "attributes": { + "username": "Admin", + "displayName": "Admin", + "avatarUrl": null, + "slug": "1" + } + }, + { + "type": "users", + "id": "64", + "attributes": { + "username": "Flarum", + "displayName": "Flarum", + "avatarUrl": "https://flarum.tld/assets/avatars/Z4hEncw0ndVqZ8be.png", + "slug": "64" + } + }, + { + "type": "tags", + "id": "3", + "attributes": { + "name": "Welcome", + "description": "Post interesting things here", + "slug": "welcome", + "color": "#888", + "backgroundUrl": null, + "backgroundMode": null, + "icon": "fas fa-bullhorn", + "discussionCount": 30, + "position": 1, + "defaultSort": null, + "isChild": false, + "isHidden": false, + "lastPostedAt": "2022-01-05T10:20:30+00:00", + "canStartDiscussion": true, + "canAddToDiscussion": true, + "isRestricted": false + } + }, + { + "type": "posts", + "id": "668", + "attributes": { + "number": 1, + "createdAt": "2022-01-01T10:20:30+00:00", + "contentType": "comment", + "contentHtml": "

Hello World

" + } + }, + // [...] more includes for the other discussions + ] +} +``` + +### Create discussion + + POST /api/discussions + +```json +{ + "data":{ + "type": "discussions", + "attributes": { + "title": "Lorem Ipsum", + "content": "Hello World" + }, + "relationships": { + "tags": { + "data": [ + { + "type": "tags", + "id": "1" + } + ] + } + } + } +} +``` + +The response includes the ID of the new discussion: + +```json +{ + "data": { + "type": "discussions", + "id": "42", + "attributes": { + "title": "Lorem Ipsum", + "slug": "42-lorem-ipsum", + "commentCount": 1 + // [...] other attributes + }, + "relationships": { + "posts": { + "data": [ + { + "type": "posts", + "id": "58" + } + ] + }, + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + // [...] other relationships + } + }, + "included":[ + { + "type": "posts", + "id": "38", + "attributes": { + "number": 1, + "contentType": "comment", + "contentHtml": "\u003Cp\u003EHello World\u003C\/p\u003E" + // [...] other attributes + } + } + // [...] other includes + ] +} +``` + +### Create user + + POST /api/users + +```json +{ + "data": { + "attributes": { + "username": "Flarum", + "email": "flarum@example.com", + "password": "correcthorsebatterystaple" + } + } +} +``` + +## Errors + +Flarum uses various HTTP status code and includes error descriptions that follow the [JSON:API error spec](https://jsonapi.org/format/#errors). + +Below are a few common errors you might encounter when using the REST API: + +### CSRF Token Mismatch + +If you receive a 400 HTTP error with `csrf_token_mismatch` message, it means the `Authorization` header is absent or invalid and Flarum attempted to authenticate through the session cookie. + +```json +{ + "errors": [ + { + "status": "400", + "code": "csrf_token_mismatch" + } + ] +} +``` + +### Validation errors + +Validation errors are returned with 422 HTTP status code. The name of the invalid field is returned as the `pointer` value. There can be multiple errors for a single field at the same time. + +```json +{ + "errors": [ + { + "status": "422", + "code": "validation_error", + "detail": "The username has already been taken.", + "source":{ + "pointer":"\/data\/attributes\/username" + } + }, + { + "status": "422", + "code": "validation_error", + "detail": "The email has already been taken.", + "source": { + "pointer":"\/data\/attributes\/email" + } + } + ] +} +``` diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/scheduler.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/scheduler.md new file mode 100644 index 000000000..6123ce7c3 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/scheduler.md @@ -0,0 +1,55 @@ +# Scheduler + +The Flarum scheduler allows extensions to automate certain tasks effortlessly. In this guide we will see how to set it up. We won't go into the details of cron itself, but if you want to read more about it, I suggest you take a look at [this Wikipedia article](https://en.wikipedia.org/wiki/Cron) on cron. + +## Why should I care? + +Quite simply, a growing list of extensions now support handling certain functions automatically for you, completely behind the scenes. Wondering why `fof/drafts` 'scheduled drafts' are not posting, or `fof/best-answer` 'remind users to set a best answer after X days' does not fire? That'll be because they will setup themselves with the scheduler service, but without a one-liner cron job, nothing will happen! + +## What extensions currently use the scheduler? + +Some of the most popular examples are the following: + +- [FoF Best Answer](https://github.com/FriendsOfFlarum/best-answer) +- [FoF Drafts](https://github.com/FriendsOfFlarum/drafts) +- [FoF Sitemap](https://github.com/FriendsOfFlarum/sitemap) +- [FoF Open Collective](https://github.com/FriendsOfFlarum/open-collective) +- [FoF Github Sponsors](https://github.com/FriendsOfFlarum/github-sponsors) + +## Ok, let's get this setup! + +Most (if not all) Linux distros either come with, or can have, cron installed. For example, on Debian and Ubuntu based systems, you can install `cron` like this: + +``` +sudo apt-get update +sudo apt-get install cron +``` + +In case you are using a RHEL based Linux distribution (CentOS, AlmaLinux, Rocky Linux...), install cron like this: + +``` +sudo dnf update +sudo dnf install crontabs +``` + +Once you have cron installed, let's create the one and only entry you need for Flarum: + +``` +crontab -e +``` + +This will open the cron editor. You may or may not have other entries there. Add this line, and remember to leave an empty line at the bottom. + +``` +* * * * * cd /path-to-your-project && php flarum schedule:run >> /dev/null 2>&1 +``` + +`* * * * *` tells cron to run your command every minute. + +In case you want to use a different value and don't know exactly how cron expressions work, you can use a [cron expression generator](https://crontab.guru) to easily get the desired string. + +`cd /path-to-your-project && php flarum schedule:run` executes Flarum's scheduler to trigger any tasks currently waiting to be run. If PHP isn't in your system's path, you may need to experiment with setting the full path to PHP. + +Lastly `>> /dev/null 2>&1` suppresses any output from the command. + +Voila! Now any extension that registers a task to run, anything from every minute to daily, monthly, yearly - whatever - will now run on your server. diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/themes.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/themes.md new file mode 100644 index 000000000..8c0aa5053 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/themes.md @@ -0,0 +1,29 @@ +# Aspetto e Temi + +Anche se abbiamo lavorato duramente per rendere Flarum il più bello possibile, ogni comunità probabilmente vorrà apportare alcune modifiche grafiche o di stile per adattarlo alle proprie esigenze. + +## Pannello di amministrazione + +The [admin dashboard](admin.md)'s Appearance page is a great first place to start customizing your forum. Da qui infatti si può: + +- Scegliere i colori principali del forum +- Attivare o meno la dark mode e scegliere il colore dell'header +- Caricare il tuo logo e favicon (l'icona visualizzata ai browser) +- Aggiungere html per personalizare header e footer +- Aggiungere [LESS/CSS](#css-theming) per cambiare la visualizzazione degli elementi + +## Il CSS nei temi + +CSS è un linguaggio per fogli di stile che indica ai browser come visualizzare gli elementi di una pagina web. Ci consente di modificare qualsiasi cosa, dai colori ai caratteri, alla dimensione degli elementi e al posizionamento delle animazioni. L'aggiunta di CSS personalizzati può essere un ottimo modo per modificare l'aspetto di Flarum in modo che corrisponda al tema del tuo sito. + +Un tutorial CSS va oltre lo scopo di questa documentazione, ma ci sono molte ottime risorse online per apprendere le basi dei fogli di stile. + +:::tip + +Flarum utilizza LESS, il che rende più facile scrivere CSS consentendo variabili, condizionali e funzioni. + +::: + +## Estensioni + +La flessibilità di Flarum nel [sistema di estensioni](extensions.md) ti consente di aggiungere, rimuovere o modificare praticamente ogni parte di Flarum. Se si desidera apportare modifiche sostanziali ai temi oltre a cambiare colori / dimensioni / stili, un'estensione personalizzata è sicuramente la strada da percorrere. Per sapere come creare un'estensione, dai un'occhiata alla [documentazione sulle estensioni](extend/README.md)! diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md new file mode 100644 index 000000000..0a287f292 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md @@ -0,0 +1,56 @@ +# Risoluzione dei problemi + +Se Flarum non si installa o non funziona come previsto, la prima cosa da fare è controllare di nuovo se il proprio ambiente soddisfa [i requisiti necessari](install.md#server-requirements). Se ti manca qualcosa che è necessaria per l'esecuzione di Flarum, dovrai prima rimediare. + +Successivamente, dovresti impiegare alcuni minuti per cercare nel [Forum di supporto](https://discuss.flarum.org/t/support) e nell' [issue tracker](https://github.com/flarum/core/issues). È possibile che qualcuno abbia già segnalato il problema e una soluzione sia disponibile o in arrivo. Se hai cercato a fondo e non riesci a trovare alcuna informazione sul problema, è ora di iniziare la risoluzione dei problemi. + +## Step 0: Activate debug mode + +:::danger Salta in produzione + +Questi strumenti di debug sono molto utili, ma possono esporre informazioni che non dovrebbero essere pubbliche. These are fine if you're on a staging or development environment, but if you don't know what you're doing, skip this step when on a production environment. + +::: + +Prima di procedere, dovresti abilitare gli strumenti di debug di Flarum. Apri semplicemente il file **config.php** con un editor di testo, modifica il valore `debug` su `true`, e salva il file. uesto farà sì che Flarum visualizzi messaggi di errore dettagliati, dandoti un'idea di cosa non va. + +Se hai visto pagine vuote e la modifica sopra non aiuta, prova a impostare `display_errors` su `On` nel file di configurazione **php.ini**. + +## Step 1: Correzioni comuni + +A lot of issues can be fixed with the following: + +* Pulisci la cache del browser +* Pulisci la cache del backend con il comando [`php flarum cache:clear`](console.md). +* Assicurati che il tuo database sia aggiornato con il comando [`php flarum migrate`](console.md). +* Assicurati che [la configurazione email](mail.md) nel tuo pannello di amministrazione sia corretta: una configurazione e-mail non valida causerà errori durante la registrazione, la reimpostazione di una password, la modifica delle e-mail e l'invio di notifiche. +* Controlla che il tuo file `config.php` sia corretto. Ad esempio, assicurati di utilizzare un `url` corretto. +* One potential culprit could be a custom header, custom footer, or custom LESS. If your issue is in the frontend, try temporarily removing those via the Appearance page of the admin dashboard. + +Dovrai anche dare un'occhiata all'output di [`php flarum info`](console.md) per assicurarti che nulla di importante sia fuori posto. + +## Step 2: Riproduci il problema + +Prova a far sì che il problema si ripresenti. Presta molta attenzione a ciò che stai facendo quando si verifica. Succede ogni volta o solo di tanto in tanto? Prova a cambiare un'impostazione che ritieni possa influire sul problema o l'ordine in cui stai facendo le cose. Succede in alcune condizioni, ma non in altre? + +Se hai recentemente aggiunto o aggiornato un'estensione, dovresti disabilitarla temporaneamente per vedere se questo risolve il problema. Assicurati che tutte le tue estensioni siano destinate ad essere utilizzate con la versione di Flarum che stai utilizzando. Le estensioni obsolete possono causare una serie di problemi. + +Da qualche parte lungo la strada potresti avere un'idea di cosa sta causando il tuo problema e trovare un modo per risolverlo. Ma anche se ciò non accade, probabilmente ti imbatterai in alcuni preziosi indizi che ci aiuteranno a capire cosa sta succedendo, una volta che avrai presentato la tua segnalazione di bug. + +## Step 3: Raccogli informazioni + +Se sembra che avrai bisogno di aiuto per risolvere il problema, è ora di fare sul serio nella raccolta dei dati. Cerca messaggi di errore o altre informazioni sul problema nei seguenti punti: + +* Visualizzato nella pagina attuale +* Visualizzato nella console del browser (Chrome: More tools -> Developer Tools -> Console) +* Registrato nel registro degli errori del server (es. `/var/log/nginx/error.log`) +* Registrato nel log PHP-FPM's (es. `/var/log/php7.x-fpm.log`) +* Registrato da Flarum (`storage/logs/flarum.log`) + +Copia i messaggi in un file di testo e prendi nota di quando si è verificato l'errore, cosa stavi facendo in quel momento e così via. Assicurati di includere tutti gli approfondimenti che potresti aver raccolto sulle condizioni in cui il problema si verifica e non si verifica. Aggiungi quante più informazioni possibili sul tuo ambiente server: versione del sistema operativo, versione del server web, versione e gestore di PHP, ecc. + +## Step 4: Prepara un report + +Dopo aver raccolto tutte le informazioni possibili sul problema, sei pronto per presentare una segnalazione di bug. Si prega di seguire le istruzioni [per segnalare bug](bugs.md). + +Se scopri qualcosa di nuovo sul problema dopo aver inviato la segnalazione, aggiungi tali informazioni in fondo al tuo post originale. È una buona idea presentare un rapporto anche se hai risolto il problema da solo, poiché anche altri utenti potrebbero trarre vantaggio dalla tua soluzione. Se hai trovato una soluzione temporanea al problema, assicurati mettercene a conoscenza. \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/version-1.x/update.md b/i18n/it/docusaurus-plugin-content-docs/version-1.x/update.md new file mode 100644 index 000000000..fde68ef57 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/version-1.x/update.md @@ -0,0 +1,110 @@ +# Aggiornare la versione di Flarum + +## From the Admin Dashboard + +:::info + +If you have the extension manager extension installed you can simply run the update from its interface and skip this page entirely. + +::: + +--- + +To update Flarum, you'll need to use [Composer](https://getcomposer.org). If you're not familiar with it (although you should be, because you need it to install Flarum), read [our guide](composer.md) for information on what it is and how to set it up. + +If updating across major versions (e.g. <=0.1.0 to 1.x.x, 1.x.x to 2.x.x, ...), make sure to read the appropriate "major version update guide" before running the general upgrade steps. + +## General Steps + +**Step 1:** Make sure all your extensions have versions compatible with the Flarum version you're trying to install. This is only needed across major versions (e.g. you probably don't need to check this if upgrading from v1.0.0 to v1.1.0, assuming your extensions follow recommended versioning). You can check this by looking at the extension's [Discuss thread](https://discuss.flarum.org/t/extensions), searching for it on [Packagist](http://packagist.org/), or checking databases like [Extiverse](https://extiverse.com). You'll need to remove (not just disable) any incompatible extensions before updating. Please be patient with extension developers! + +**Step 2:** Take a look at your `composer.json` file. Unless you have a reason to require specific versions of extensions or libraries, you should set the version string of everything except `flarum/core` to `*` (including `flarum/tags`, `flarum/mentions`, and other bundled extensions). Make sure `flarum/core` is NOT set to `*`. If you're targeting a specific version of Flarum, set `flarum/core` to that (e.g. `"flarum/core": "v0.1.0-beta.16`). If you just want the most recent version, use `"flarum/core": "^1.0"`. + +**Step 3:** If your local install uses [local extenders](extenders.md), make sure they are up to date with changes in Flarum. + +**Step 4:** We recommend disabling third-party extensions in the admin dashboard before updating. This isn't strictly required, but will make debugging easier if you run into issues. + +**Step 5:** Make sure your PHP version is supported by the version of Flarum you are trying to upgrade to, and that you are using Composer 2 (`composer --version)`. + +**Step 6:** Finally, to update, run: + +``` +composer update --prefer-dist --no-plugins --no-dev -a --with-all-dependencies +php flarum migrate +php flarum cache:clear +``` + +**Step 7:** If applicable, restart your PHP process and opcache. + +## Major Version Update Guides + +### Updating from Beta (<=0.1.0) to Stable v1 (^1.0.0) + +1. Do steps 1-5 above. +2. Change the version strings of all bundled extensions (`flarum/tags`, `flarum/mentions`, `flarum/likes`, etc) in `composer.json` from `^0.1.0` to `*`. +3. Change `flarum/core`'s version string in `composer.json` from `^0.1.0` to `^1.0`. +4. Remove the `"minimum-stability": "beta",` line from your `composer.json` +5. Do steps 6 and 7 above. + +## Troubleshooting Issues + +Mentre Flarum è in fase beta, le istruzioni e le modalità di aggiornamento verranno scritte direttamente nel forum inglese: [annunci sui rilasci](https://discuss.flarum.org/t/blog?sort=newest). + +### Errors While Updating + +Here we'll go through several common types of issues while trying to update Flarum. + +--- + +If the output is short and contains: + +``` +Nothing to modify in lock file +``` + +Or does not list `flarum/core` as an updated package, and you are not on the latest flarum version: + +- Revisit step 2 above, make sure that all third party extensions have an asterisk for their version string. +- Make sure your `flarum/core` version requirement isn't locked to a specific minor version (e.g. `v0.1.0-beta.16` is locked, `^1.0.0` isn't). If you're trying to update across major versions of Flarum, follow the related major version update guide above. + +--- + +For other errors, try running `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO` + +If the output looks something like this: + +``` +flarum/flarum - requires flarum/core (v0.1.0-beta.15) +fof/moderator-notes 0.4.4 requires flarum/core (>=0.1.0-beta.15 <0.1.0-beta.16) +jordanjay29/flarum-ext-summaries 0.3.2 requires flarum/core (>=0.1.0-beta.14 <0.1.0-beta.16) +flarum/core v0.1.0-beta.16 requires dflydev/fig-cookies (^3.0.0) +flarum/flarum - does not require dflydev/fig-cookies (but v2.0.3 is installed) +flarum/core v0.1.0-beta.16 requires franzl/whoops-middleware (^2.0.0) +flarum/flarum - does not require franzl/whoops-middleware (but 0.4.1 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/bus (^8.0) +flarum/flarum - does not require illuminate/bus (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/cache (^8.0) +flarum/flarum - does not require illuminate/cache (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/config (^8.0) +flarum/flarum - does not require illuminate/config (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/container (^8.0) +flarum/flarum - does not require illuminate/container (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/contracts (^8.0) +flarum/flarum - does not require illuminate/contracts (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/database (^8.0) +flarum/flarum - does not require illuminate/database (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/events (^8.0) +flarum/flarum - does not require illuminate/events (but v6.20.19 is installed) +... (this'll go on for a bit) +``` + +It is very likely that some of your extensions have not yet been updated. + +- Revisit step 1 again, make sure all your extensions have versions compatible with the core version you want to upgrade to. Remove any that don't. +- Make sure you're running `composer update` with all the flags specified in the update step. + +If none of this fixes your issue, feel free to reach out on our [Support forum](https://discuss.flarum.org/t/support). Make sure to include the output of `php flarum info` and `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO`. + +### Errori Dopo L'Aggiornamento + +Se non riesci ad accedere al tuo forum dopo l'aggiornamento, segui le nostre [istruzioni per la risoluzione dei problemi](troubleshoot.md). diff --git a/i18n/tr/docusaurus-plugin-content-docs/current.json b/i18n/tr/docusaurus-plugin-content-docs/current.json index ac470d0fc..72eb041ab 100644 --- a/i18n/tr/docusaurus-plugin-content-docs/current.json +++ b/i18n/tr/docusaurus-plugin-content-docs/current.json @@ -1,6 +1,6 @@ { "version.label": { - "message": "Sonraki", + "message": "2.x", "description": "The label for version current" }, "sidebar.guideSidebar.category.Introduction": { @@ -39,4 +39,4 @@ "message": "Internal Docs", "description": "The label for category Internal Docs in sidebar internalSidebar" } -} \ No newline at end of file +} diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/README.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/README.md new file mode 100644 index 000000000..7e17cf8e2 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/README.md @@ -0,0 +1,45 @@ +- - - +slug: / +- - - + +# Flarum Hakkında + +Flarum, web siteniz için oldukça basit bir tartışma platformudur. Başarılı bir topluluk yürütmek için ihtiyacınız olan tüm özelliklerle birlikte kullanımı hızlı ve kolaydır. Aynı zamanda son derece genişletilebilir olup, en üst düzeyde özelleştirilebilirliğe olanak tanır. + +![Flarum Ana Sayfa Ekran Görüntüsü](/en/img/home_screenshot.png) + +## Hedefler + +Flarum, [esoTalk](https://github.com/esotalk/esoTalk) ve [FluxBB](https://fluxbb.org)'nin birleşik halefidir. Şu şekilde tasarlanmıştır: + +* **Hızlı ve basit.** Dağınıklık yok, şişkinlik yok, karmaşık bağımlılıklar yok. Flarum PHP ile oluşturulmuştur, bu nedenle dağıtımı hızlı ve kolaydır. Arayüz, küçük bir ayak izine sahip, performanslı bir JavaScript çerçevesi olan [Mithril](https://mithril.js.org) tarafından desteklenmektedir. + +* **Güzel ve duyarlı.** Bu, insanlar için forum yazılımıdır. Flarum, kutudan çıkar çıkmaz tüm platformlarda tutarlı ve sezgisel olacak şekilde dikkatle tasarlanmıştır. + +* **Güçlü ve genişletilebilir.** Flarum'u topluluğunuza uyacak şekilde özelleştirin, genişletin ve entegre edin. Flarum’un mimarisi, [Güçlü Uzantı API'si](/extend/) ile inanılmaz derecede esnektir. + +* **Ücretsiz ve açıktır.** Flarum, [MIT lisansı](https://github.com/flarum/flarum/blob/master/LICENSE) altında yayınlanmıştır. + +[Flarum'a yönelik felsefemiz ve değerlerimiz](https://discuss.flarum.org/d/28869-flarum-philosophy-and-values) hakkında daha fazla bilgi edinebilirsiniz. + +## Flarum Projesine Yardım Edin + +Flarum, gönüllüler tarafından bakımı yapılan ve yönetilen [ücretsiz, açık kaynaklı](https://github.com/flarum/core) bir yazılımdır. Flarum'u geliştirmemize ve genişletmemize yardımcı olması için topluluk katkılarına güveniyoruz. + +🧑‍💻 Eğer bir geliştiriciyseniz, Flarum'un temeline veya paketlenmiş uzantılarına katkıda bulunmayı düşünebilirsiniz. Bu, Flarum'a yardımcı olmanın en etkili yolu ve çalışmalarınızın büyük bir etkisi olabilir: milyonlarca son kullanıcıya sahip binlerce Flarum sitesi mevcuttur. + +🧩Eksik olduğunu düşündüğünüz bir özellik veya aklınıza gelen bir tema fikri varsa, [özel bir uzantı yazmak](extend/README.md) Flarum'u siz ve diğerleri için çok daha iyi hale getirecektir. + +✒️ Teknik yazım konusunda deneyiminiz varsa, [belgelerimize](https://github.com/flarum/docs/issues) yapacağınız katkılar gelecekteki kullanıcıların, yöneticilerin ve geliştiricilerin Flarum'dan en iyi şekilde yararlanmasına yardımcı olabilir. + +🌐 Birden fazla dil konuşuyorsanız Flarum'un dünya çapındaki sayısız kullanıcı tarafından erişilebilir olmasına yardımcı olmak için [çevirilere katkıda bulunabilirsiniz](extend/language-packs.md). + +💸 Flarum Vakfı, Flarum'dan para kazanmıyor ancak ödenmesi gereken faturaları var. [GitHub Sponsorları](https://github.com/sponsors/flarum) veya [OpenCollective](https://opencollective.com/flarum) aracılığıyla yapılan bağışlar her zaman minnetle alınır. Geçmişte, bazı temel geliştiricilerimizi finansal olarak da destekleyebildik, böylece onların Flarum'da yarı zamanlı çalışabilmesini sağladık. Maddi desteğiniz olmadan bu mümkün olmazdı. + +🧑‍🤝‍🧑 Flarum geliştirme hakkında konuşmak, örneğinizle ilgili yardım almak veya sadece harika insanlarla tanışmak için [topluluğumuza](https://discuss.flarum.org) katılın! Flarum konusunda deneyiminiz varsa yeni başlayanlara da yardımcı olabilirsiniz! + +🐛 Canınızı sıkan bir hata ya da aklınızda bir özellik fikri varsa siz bize söylemediğiniz sürece bunu bilemeyiz! Hataları, önerileri ve gelecekteki geliştirme planlarını [GitHub sorunları](https://github.com/flarum/core/issues) aracılığıyla takip ediyoruz. Zaten açık bir sorun varsa, beğeniler ve (yapıcı) ek bilgiler eklemek çok yararlı olabilir! + +📣 Ve eğer Flarum'u seviyorsanız, lütfen bunun hakkında blog yazmayı/tweetlemeyi/konuşmayı düşünün! Flarum'dan haberdar olan daha fazla insan, daha fazla insanın Flarum'la etkileşime geçmesine ve dolayısıyla daha fazla aktiviteye, daha iyi uzantılara ve daha hızlı gelişime yol açar. + +Olağanüstü topluluğumuz olmadan Flarum mümkün olmazdı. Katkıda bulunmak istiyorsanız daha fazla bilgi için [geliştirici katkısı](contributing.md) ve [diğer katkı](contributing-docs-translations.md) belgelerimize bakın. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/admin.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/admin.md new file mode 100644 index 000000000..3b3ed3318 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/admin.md @@ -0,0 +1,13 @@ +# Yönetici Gösterge Tablosu + +Flarum Yönetici Panosu, forumunuzu yönetmek için kullanıcı dostu bir arayüzdür. Yalnızca "Yönetici" grubundaki kullanıcılar tarafından kullanılabilir. Yönetici panosuna erişmek için ekranın sağ üst köşesindeki **Adınıza** tıklayın ve **Yönetim**'i seçin. + +Yönetici Kontrol Panelinde aşağıdaki bölümler bulunur: +- **Kontrol Paneli** - İstatistikleri ve diğer ilgili bilgileri içeren ana Yönetici Kontrol Panelini gösterir. +- **Temel Bilgiler** - Ad, Açıklama ve Hoş Geldiniz Banner'ı gibi temel forum ayrıntılarını ayarlama seçeneklerini gösterir. +- **E-posta** - E-Posta ayarlarınızı yapılandırmanıza olanak tanır. Daha fazla bilgi için [buraya](https://docs.flarum.org/mail) bakın. +- **İzinler** - Her kullanıcı grubunun izinlerini gösterir ve genel ve belirli kapsamları yapılandırmanıza olanak tanır. +- **Görünüm** - Forumun renklerini, markasını özelleştirmenize ve özelleştirme için ek CSS eklemenize olanak tanır. +- **Kullanıcılar** - Forumdaki tüm kullanıcıların sayfalandırılmış bir listesini sağlar ve size kullanıcıyı düzenleme veya idari işlemler gerçekleştirme olanağı verir. + +Yönetici Kontrol Paneli, yukarıda bahsedilen bölümlerin dışında, _Özellikler_ bölümü altında Uzantılarınızı (Etiketler gibi flarum çekirdek uzantıları dahil) yönetmenize de olanak tanır. Forum temasını değiştiren veya birden fazla dil kullanmanıza olanak tanıyan uzantılar, sırasıyla _Temalar_ ve _Diller_ bölümünde kategorize edilmiştir. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/bugs.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/bugs.md new file mode 100644 index 000000000..85e8ea193 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/bugs.md @@ -0,0 +1,28 @@ +# Reporting Bugs + +:::danger Security Vulnerabilities + +If you discover a security vulnerability within Flarum, please follow our [security policy](https://github.com/flarum/core/security/policy) so we can address it promptly. + +::: + +Thank you for helping us test Flarum. We're happy to have you on the team! We need people who can *troubleshoot issues patiently* and *communicate them clearly*. As you probably know, good bug reporting takes some time and effort. If you're fine with that, then let's get started! + +## Duplicates + +Found a bug already? Wonderful! We'd love to hear about it — but first you should check around to make sure you're not wasting your time on a known issue: + +- Search our [Support forum](https://discuss.flarum.org/t/support) to see if it's already been reported. +- We could be working on a fix, so search our [issue tracker](https://github.com/flarum/core/issues) too. + +If you've searched *thoroughly* and come up empty-handed, we'll welcome your report. If it's just a simple issue (a misspelled word or graphics glitch, for example) skip to the next paragraph. But if you're seeing errors, or something is clearly broken, we'll need you to gather some information first. Please head over to our [Troubleshooting](troubleshoot.md) guide and follow the instructions there. Collect as much info as you can! + +## Reporting + +We track issues on GitHub. Make sure you open your issue in the [correct repository](https://github.com/flarum), and fill out all of the information in the Bug Report template. + +If you can, check if the issue is reproducible with the latest version of Flarum. If you are using a pre-release or development version, please indicate the specific version you are using. + +Remember: the goal of a bug report is to make it easy for us to replicate the bug and fix it. You might want to read [this article](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html) for some useful tips on how to write an effective bug report. It is **required** that you clearly describe the steps necessary to reproduce the issue you are running into. Issues with no clear reproduction steps will not be triaged. If an issue labeled "needs verification" receives no further input from the issue author for more than 5 days, it will be closed. + +Once you've posted your report, we'd ask that you please *follow the discussion* and wait patiently. We may need to ask for further details or clarification; but we've always got plenty to do, and it could be a while before we can give your report the time it deserves. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md new file mode 100644 index 000000000..6041c1b6e --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md @@ -0,0 +1,51 @@ +# Davranış Kuralları + +### _Flarum Topluluğuna Hoş Geldiniz!_ + +... Ve bize katıldığınız için teşekkürler! Flarum için heyecanlıyız ve aynı şekilde hisseden insanlarla tanışmaktan her zaman mutluyuz. *Herkesin* Flarum ve Flarum topluluğundan en iyi şekilde yararlanmasını istiyoruz, bu nedenle bu yönergeleri okuyup uygulamanızı rica ediyoruz. Bunlar, forumumuzu, Discord sohbetini, GitHub'da iletişim kurmayı veya Flarum topluluğu olmadan başka herhangi bir iletişim biçimini kullanıyor olsanız da geçerlidir. + +### Her Şeyden Önce Sakin Olun! + +Hepimiz Flarum hakkında konuşmak ve onu daha iyi bir uygulama haline getirmek için birlikte çalışmak için buradayız. Fikirleri eleştirmek (elbette gerekçeli argümanlar aracılığıyla) bunun önemli bir parçasıdır. Ama kendimizi kaptırıp kişisel saldırılara geçmeyelim, çünkü olumsuzluk sadece araya girer. Aşağıdakilerden kaçınmanızı rica ediyoruz: + +- Saldırgan veya taciz edici dil ve ayrıca her türlü nefret söylemi +- Başkalarını taciz etmeyi, taklit etmeyi veya karalamayı amaçlayan gönderiler +- Gönderilen içeriğin gereksiz yere silinmesi +- Başkalarının özel bilgilerini kötüye kullanma veya ifşa etme girişimleri +- Müstehcen içerik +- Spam, kimlik avı gönderileri ve bu siteyi tahrif etmeye yönelik her türlü eylem +- Yazılım korsanlığı ve benzeri konuların tartışılması + +*Yukarıdakilerin tümü moderatör eylemi gerekçesidir.* Başka bir üyeyle bir sorununuz varsa, lütfen onlarla kendi başınıza yüzleşmemenizi rica ederiz. Forumdaysa, lütfen söz konusu gönderide *Report* komutunu kullanın, ardından durumla ilgilenmesi için bunu yetkiliye bırakın. Aksi takdirde ihlali [iletişim sayfamızdaki](https://flarum.org/foundation/contact) Yasal seçeneğini kullanarak bildirin. + +Moderatörlerimiz, saldırgan veya iletişim akışını aksatan herhangi bir içeriği düzenleyebilir veya silebilir. Ciddi veya tekrarlanan suçlar, ihlalde bulunan kullanıcının hesabının askıya alınmasına neden olabilir. Yani, bilirsin, *sakin ol*. 😎 + +### Duyulmasını Sağlayın + +Yeni bir tartışma başlatmak ister misiniz? Öncelikle [SSS](faq.md) bölümünü okuduğunuzdan ve proje hakkında tam olarak bilgi sahibi olduğunuzdan emin olmak için bağlantıları takip ettiğinizden emin olun. Daha sonra foruma göz atmak için biraz zaman ayırın, [etiket sistemi](https://discuss.flarum.org/tags) hakkında bilgi edinin ve konunuzla ilgili anahtar kelimeler için birkaç arama yapın: *birisi çoktan bunun hakkında bir tartışma başlamış olabilir!* + +Bir tartışma başlatmaya hazır olduğunuzdan emin olduğunuzda lütfen aşağıdaki noktaları aklınızda bulundurun: + +- Ona iyi bir başlık ver! Başlığınız ne hakkında konuşmak istediğinizi netleştirirse en iyi sonuçları alırsınız. +- Doğru etiketleri seçin. Bu, gönderinizin hemen okunma ve yanıtlanma olasılığını artıracaktır. +- Aynı tartışma ilgili tekrar tekrar *yayınlamayın*, çünkü bunu yapmak ters etki yaratır. +- Çok dilli kullanıma ayrılmış bir etiket kullanmıyorsanız *yalnızca İngilizce yayınlayın.* Gönderilerinizi anlamazsak size yardımcı olamayız. +- Unutmayın, yazılarınızı imzalamanıza gerek yok. Kim olduğunuzu bize bildirmek için profilinize bakıyoruz. + +Lütfen işleri organize etmemize yardımcı olmak için çaba gösterin. Toparlanmak için harcanan zaman, sizi tanımak, sorunlarınızı tartışmak ve Flarum hakkında konuşmak için harcayamayacağımız zamandır. Ve sonuçta, hepimiz yapmak için buradayız! + +### Yanıtınızı Sayın + +Başkalarının fikirlerinizi okuyup dikkate alması umuduyla bir tartışmaya katılmak için zaman ayırıyorsunuz. Öyleyse neden yanıtınızı okumaya değer kılmak için çaba harcamıyorsunuz? + +- Bir başlığı yanıtlamayın. İlk gönderiyi *okumak* için biraz zaman ayırın ve en azından tartışmanın geri kalanına *göz atın*. +- Cevabınızın tartışmaya katkıda bulunup bulunmadığını kendinize sorun. Olmazsa, yayınlamadan önce biraz daha düşünün. +- Birisiyle aynı fikirde olmak için tek kelimelik yazılar yapmaktan kaçının; bunun için "Like" düğmesini kullanabilirsiniz. +- Yeterli olduğunda arka arkaya birden fazla gönderi yapmaktan kaçının. Bu bir forum, sohbet odası değil. +- Cevabınız tartışmanın yönünü değiştirecekse, bunun yerine yeni bir tartışma başlatmayı düşünün. +- Test olarak biraz saçma sapan yayınlamak istiyorsanız, lütfen bunu [Test Posting](https://discuss.flarum.org/t/sandbox) etiketinde yapın. +- Yanıtlarınızın, kapsayıcı bir topluluğa izin vermek için yapıcı geri bildirim ve destek sağladığından emin olun. + +Hiç kimse ara sıra yapılan şakadan veya akıllıca sözlerden şikayet etmeyecek. Ruh halini hafif tutmayı seviyoruz! Ama aynı zamanda her şeyi üretken tutmak için, bir tartışmayı tamamen raydan çıkarmaktan kaçınmanızı istiyoruz. + +> Bu kuralları bir araya getirmedeki yardımlarından dolayı Dominion'a teşekkürler. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/composer.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/composer.md new file mode 100644 index 000000000..f8c126903 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/composer.md @@ -0,0 +1,152 @@ + +# Composer + +Flarum uses a program called [Composer](https://getcomposer.org) to manage its dependencies and extensions. You'll need to use composer if you want to: + +- Install or update Flarum through the command line +- Install, update, or remove Flarum extensions through the command line + +This guide is provided as a brief explanation of Composer. We highly recommend consulting the [official documentation](https://getcomposer.org/doc/00-intro.md) for more information. + +:::tip Paylaşımlı Hosting + +On shared hosting it is recommended to use the Extension Manager extension instead of Composer. It is a graphical interface for Composer that allows you to install, update and remove extensions without the need for SSH access. You can directly install Flarum using an archive file, without the need for Composer. With the extension manager pre-installed, check the [installation guide](install.md#installing-by-unpacking-an-archive) for more information. + +::: + +## What is Composer? + +> Composer is a tool for dependency management in PHP. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you. — [Composer Introduction](https://getcomposer.org/doc/00-intro.md](https://getcomposer.org/doc/00-intro.md)) + +Each Flarum installation consists primarily of Flarum core and a set of [extensions](extensions.md). Each of these has its own dependencies and releases. + +Back in the day, forum frameworks would manage extensions by having users upload zip files with the extension code. That seems simple enough, but issues quickly become evident: + +- Uploading random zip files from the internet tends to be a bad idea. Requiring that extensions be downloaded from a central source like [Packagist](https://packagist.org/) makes it somewhat more tedious to spam malicious code, and ensures that source code is available on GitHub for free/public extensions. +- Let's say Extension A requires v4 of some library, and Extension B requires v5 of that same library. With a zip-based solution, either one of the two dependencies could override the other, causing all sorts of inconsistent problems. Or both would attempt to run at once, which would cause PHP to crash (you can't declare the same class twice). +- Zip files can cause a lot of headache if trying to automate deployments, run automated tests, or scale to multiple server nodes. +- There is no good way to ensure conflicting extension versions can't be installed, or that system PHP version and extension requirements are met. +- Sure, we can upgrade extensions by replacing the zip file. But what about upgrading Flarum core? And how can we ensure that extensions can declare which versions of core they're compatible with? + +Composer takes care of all these issues, and more! + +## Flarum and Composer + +When you go to [install Flarum](install.md#installing), you're actually doing 2 things: + +1. Downloading a boilerplate "skeleton" for Flarum. This includes an `index.php` file that handles web requests, a `flarum` file that provides a CLI, and a bunch of web server config and folder setup. This is taken from the [`flarum/flarum` github repository](https://github.com/flarum/flarum), and doesn't actually contain any of the code necessary for Flarum to run. +2. Installing `composer` packages necessary for Flarum, namely Flarum core, and several bundled extensions. These are called by the `index.php` and `flarum` files from step 1, and are the implementation of Flarum. These are specified in a `composer.json` file included in the skeleton. + +When you want to update Flarum or add/update/remove extensions, you'll do so by running `composer` commands. Each command is different, but all commands follow the same general process: + +1. Update the `composer.json` file to add/remove/update the package. +2. Do a bunch of math to get the latest compatible versions of everything if possible, or figure out why the requested arrangement is impossible. +3. If everything works, download new versions of everything that needs to be updated. If not, revert the `composer.json` changes + +When running `composer.json` commands, make sure to pay attention to the output. If there's an error, it'll probably tell you if it's because of extension incompatibilities, an unsupported PHP version, missing PHP extensions, or something else. + +### The `composer.json` File + +As mentioned above, the entire composer configuration for your Flarum site is contained inside the `composer.json` file. You can consult the [composer documentation](https://getcomposer.org/doc/04-schema.md) for a specific schema, but for now, let's go over an annotated `composer.json` from `flarum/flarum`: + +```json +{ + // This following section is mostly just metadata about the package. + // For forum admins, this doesn't really matter. + "name": "flarum/flarum", + "description": "Delightfully simple forum software.", + "type": "project", + "keywords": [ + "forum", + "discussion" + ], + "homepage": "https://flarum.org/", + "license": "MIT", + "authors": [ + { + "name": "Flarum", + "email": "info@flarum.org", + "homepage": "https://flarum.org/team" + } + ], + "support": { + "issues": "https://github.com/flarum/core/issues", + "source": "https://github.com/flarum/flarum", + "docs": "https://flarum.org/docs/" + }, + // End of metadata + + // This next section is the one we care about the most. + // It's a list of packages we want, and the versions for each. + // We'll discuss this shortly. + "require": { + "flarum/core": "^1.0", + "flarum/approval": "*", + "flarum/bbcode": "*", + "flarum/emoji": "*", + "flarum/lang-english": "*", + "flarum/flags": "*", + "flarum/likes": "*", + "flarum/lock": "*", + "flarum/markdown": "*", + "flarum/mentions": "*", + "flarum/nicknames": "*", + "flarum/pusher": "*", + "flarum/statistics": "*", + "flarum/sticky": "*", + "flarum/subscriptions": "*", + "flarum/suspend": "*", + "flarum/tags": "*" + }, + + // Various composer config. The ones here are sensible defaults. + // See https://getcomposer.org/doc/06-config.md for a list of options. + "config": { + "preferred-install": "dist", + "sort-packages": true + }, + + // If composer can find a stable (not dev, alpha, or beta) version + // of a package, it should use that. Generally speaking, production + // sites shouldn't run beta software unless you know what you're doing. + "prefer-stable": true +} +``` + +Let's focus on that `require` section. Each entry is the name of a composer package, and a version string. To read more about version strings, see the relevant [composer documentation](https://semver.org/). + +For Flarum projects, there's several types of entries you'll see in the `require` section of your root install's `flarum/core`: + +- You MUST have a `flarum/core` entry. This should have an explicit version string corresponding to the major release you want to install. For Flarum 1.x versions, this would be `^1.0`. +- You should have an entry for each extension you've installed. Some bundled extensions are included by default (e.g. `flarum/tags`, `flarum/suspend`, etc), [others you'll add via composer commands](extensions.md). Unless you have a reason to do otherwise (e.g. you're testing a beta version of a package), we recommend using an asterisk as the version string for extensions (`*`). This means "install the latest version compatible with my flarum/core". +- Some extensions / features might require PHP packages that aren't Flarum extensions. For example, you need the guzzle library to use the [Mailgun mail driver](mail.md). In these cases, the instructions for the extension/feature in question should explain which version string to use. + +## How to install Composer? + +As with any other software, Composer must first be [installed](https://getcomposer.org/download/) on the server where Flarum is running. There are several options depending on the type of web hosting you have. + +### Dedicated Web Server + +In this case you can install composer as recommended in the Composer [guide](https://getcomposer.org/doc/00-intro.md#system-requirements) + +### Managed / Shared hosting + +If Composer is not preinstalled (you can check this by running `composer --version`), you can use a [manual installation](https://getcomposer.org/composer-stable.phar). Just upload the composer.phar to your folder and run `/path/to/your/php7 composer.phar COMMAND` for any command documented as `composer COMMAND`. + +:::danger + +Some articles on the internet will mention that you can use tools like a PHP shell. If you are not sure what you are doing or what they are talking about - be careful! An unprotected web shell is **extremely** dangerous. + +::: + +## How do I use Composer? + +You'll need to use Composer over the **C**ommand-**l**ine **i**nterface (CLI). Be sure you can access your server over **S**ecure **Sh**ell (SSH). + +Once you have Composer installed, you should be able to run Composer commands in your SSH terminal via `composer COMMAND`. + +:::info Optimizations + +After most commands, you'll want to run `composer dump-autoload -a`. Essentially, this caches PHP files so they run faster. + +::: diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/config.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/config.md new file mode 100644 index 000000000..59a6e2328 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/config.md @@ -0,0 +1,35 @@ +# Yapılandırma Dosyası + +Flarum yapılandırmasının Flarum yönetici panosu (veritabanı hariç) aracılığıyla değiştirilemeyeceği tek bir yer vardır ve bu, Flarum kurulu klasörde bulunan `config.php` dosyasıdır. + +Bu dosya küçük de olsa Flarum kurulumunuzun çalışması için çok önemli olan ayrıntıları içerir. + +Dosya varsa, Flarum'a zaten kurulu olduğunu söyler. Ayrıca Flarum'a veritabanı bilgisi ve daha fazlasını sağlar. + +Örnek bir dosyayla her şeyin ne anlama geldiğine dair hızlı bir genel bakış: + +```php + false, // sorunları gidermek için kullanılan hata ayıklama modunu etkinleştirir veya devre dışı bırakır + 'offline' => false, // site bakım modunu etkinleştirir veya devre dışı bırakır. Bu, sitenizi tüm kullanıcılar (yöneticiler dahil) için erişilemez hale getirir. + 'database' => + array ( + 'driver' => 'mysql', // veritabanı sürücüsü, yani MySQL, MariaDB... + 'host' => 'localhost', // bağlantının ana bilgisayarı, harici bir hizmet kullanılmadığı sürece çoğu durumda localhost + 'database' => 'flarum', // veritabanının adı + 'username' => 'root', // veritabanı kullanıcı adı + 'password' => '', // veritabanı şifresi + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', / veritabanındaki tablolar için önek, aynı veritabanını başka bir hizmetle paylaşıyorsanız kullanışlıdır + 'port' => '3306', // veritabanı bağlantısının portu, MySQL ile varsayılan olarak 3306'dır + 'strict' => false, + ), + 'url' => 'https://flarum.localhost', // URL kurulumu, etki alanlarını değiştirirseniz bunu değiştirmek isteyeceksiniz + 'paths' => + array ( + 'api' => 'api', // /api , API'ye gider. + 'admin' => 'admin', // /admin , yönetici paneline gider. + ), +); +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/console.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/console.md new file mode 100644 index 000000000..ded88ead0 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/console.md @@ -0,0 +1,77 @@ +# Konsol + +Yönetici kontrol paneline ek olarak Flarum, forumunuzu terminal üzerinden yönetmenize yardımcı olmak için çeşitli konsol komutları sağlar. + +Konsolu kullanma: + +1. Flarum kurulumunuzun barındırıldığı sunucuya `ssh`ile bağlanın. +2. `cd` komutu ile `flarum` klasörüne git +3. `php flarum [command]` komutunu çalıştırın. + +## Varsayılan Komutlar + +### list + +Mevcut tüm yönetim komutlarını ve ayrıca yönetim komutlarını kullanma talimatlarını listeler. + +### help + +`php flarum help [command_name]` + +Belirli bir komut için yardım çıktısını görüntüler. + +`--format` seçeneğini kullanarak yardımın çıktısını başka formatlarda da yapabilirsiniz: + +`php flarum help --format=xml list` + +Mevcut komutların listesini görüntülemek için lütfen `list` komutunu kullanın. + +### info + +`php flarum info` + +Flarum'un çekirdeği ve yüklü uzantıları hakkında bilgi edinin. Bu, hata ayıklama sorunları için çok kullanışlıdır ve destek talep edilirken paylaşılmalıdır. + +### cache:clear + +`php flarum cache:clear` + +Oluşturulan js/css, metin biçimlendirici önbelleği ve önbelleğe alınmış çeviriler dahil olmak üzere arka uç Flarum önbelleğini temizler. Bu, uzantıları yükledikten veya kaldırdıktan sonra çalıştırılmalıdır ve sorun ortaya çıktığında bunu çalıştırmak ilk adım olmalıdır. + +### assets:publish + +`php flarum assets:publish` + +Publish assets from core and extensions (e.g. compiled JS/CSS, bootstrap icons, logos, etc). This is useful if your assets have become corrupted, or if you have switched [filesystem drivers](extend/filesystem.md) for the `flarum-assets` disk. + +### migrate + +`php flarum migrate` + +Bekleyen tüm geçişleri çalıştırır. Bu, veritabanını değiştiren bir uzantı eklendiğinde veya güncellendiğinde kullanılmalıdır. + +### migrate:reset + +`php flarum migrate:reset --extension [extension_id]` + +Bir uzantı için tüm geçişleri sıfırlayın. Bu, çoğunlukla uzantı geliştiricileri tarafından kullanılır, ancak bazen, bir uzantıyı kaldırıyorsanız ve tüm verilerini veritabanından temizlemek istiyorsanız bunu çalıştırmanız gerekebilir. Lütfen bunun çalışması için söz konusu uzantının şu anda yüklü olması ancak mutlaka etkinleştirilmesi gerekmediğini unutmayın. + +### schedule:run + +`php flarum schedule:run` + +Many extensions use scheduled jobs to run tasks on a regular interval. This could include database cleanups, posting scheduled drafts, generating sitemaps, etc. If any of your extensions use scheduled jobs, you should add a [cron job](https://ostechnix.com/a-beginners-guide-to-cron-jobs/) to run this command on a regular interval: + +``` +* * * * * cd /path-to-your-flarum-install && php flarum schedule:run >> /dev/null 2>&1 +``` + +This command should generally not be run manually. + +Note that some hosts do not allow you to edit cron configuration directly. In this case, you should consult your host for more information on how to schedule cron jobs. + +### schedule:list + +`php flarum schedule:list` + +This command returns a list of scheduled commands (see `schedule:run` for more information). This is useful for confirming that commands provided by your extensions are registered properly. This **can not** check that cron jobs have been scheduled successfully, or are being run. \ No newline at end of file diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md new file mode 100644 index 000000000..7b17fc28e --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md @@ -0,0 +1,26 @@ +# Docs and Translation + +## Add Documentation + +Adding documentation can help countless future Flarum users. A few ideas of what to work on: + +- User guides to help Flarum end users with some advanced Flarum features. +- More [frequently asked questions](faq.md). +- Expanded [troubleshooting](troubleshoot.md) steps. +- Step-by-step tutorials for Flarum development or installation. +- [Technical reference guides](extend/README.md) for extension developers. +- Improving literally anything else you think we should elaborate on or explain better. + +A good way to find topics to write about is to look for common questions in the [support tag](https://discuss.flarum.org/t/support) of our community. + +## Translate Flarum + +We want Flarum to be accessible to everyone, regardless of language! By contributing translations, you make it possible for many more people to enjoy Flarum. Best of all, we use user-friendly GUIs for translations, so no technical skills are necessary to help! + +Translations for Flarum core, bundled extensions, and community extensions are managed through [Weblate](https://weblate.rob006.net/projects/flarum/). + +Translations for this documentation are managed through [Crowdin](https://crowdin.com/project/flarum-docs). + +The Flarum Foundation has created the "flarum-lang" organization to support translators and ensure continuous availability of language packs. You can learn more about this by [visiting the GitHub repository](https://github.com/flarum-lang/about). + +If you want to support an existing language pack, start a new translation, or you run into issues using weblate or crowdin, it's best to [get in touch with the `flarum-lang` team](https://discuss.flarum.org/d/27519-the-flarum-language-project). diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/contributing.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/contributing.md new file mode 100644 index 000000000..f6b7b0d32 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/contributing.md @@ -0,0 +1,170 @@ +# Katkıda Bulunmak + +Flarum gelişimine katkıda bulunmak ister misiniz? Bu harika! [Bir hata raporu açmaktan](bugs.md) bir çekme isteği (PR) oluşturmaya kadar: her katkı takdir edilir ve memnuniyetle karşılanır. Flarum wouldn't be possible without our community contributions. + +Katkıda bulunmadan önce lütfen [davranış kurallarını](code-of-conduct.md) okuyun. + +Bu belge, Flarum'a kod katkısında bulunmak isteyen geliştiriciler için bir kılavuzdur. Yeni başlıyorsanız, Flarum'un nasıl çalıştığı hakkında biraz daha fazla bilgi edinmek için Uzantı belgelerindeki [Başlarken](/extend/start.md) belgelerini okumanızı öneririz. + +## Ne Üzerinde Çalışmalı + +⚡ **Have Real Impact.** There are thousands of Flarum instances, with millions of aggregate end users. By contributing to Flarum, your code will have a positive impact on all of them. + +🔮 **Shape the Future of Flarum.** We have a long backlog, and limited time. If you're willing to champion a feature or change, it's much more likely to happen, and you'll be able to enact your vision for it. Plus, our roadmap and milestones are set by our [core development team](https://flarum.org/team), and all of us started as contributors. The best road to influence is contributing. + +🧑‍💻 **Become a Better Engineer.** Our codebase is modern, and we heavily value good engineering and clean code. There's also a lot of interesting, challenging problems to solve regarding design, infrastructure, performance, and extensibility. Especially if you're a student or early in your career, working on Flarum is a great opportunity to build development skills. + +🎠 **It's Fun!** We really enjoy working on Flarum: there's a lot of interesting challenges and fun features to build. We also have an active community on [our forums](https://discuss.flarum.org) and [Discord server](https://flarum.org/chat). + +## Geliştirme Kurulumu + +Nelerin yapılması gerektiğine dair genel bir bakış için [Milestones](https://github.com/flarum/core/milestones) dönüm noktalarına göz atın. Başlaması nispeten kolay olması gereken sorunların bir listesi için [Good first issue](https://github.com/flarum/core/labels/Good%20first%20issue) etiketine bakın. If there's anything you're unsure of, don't hesitate to ask! All of us were just starting out once. + +Devam etmeyi ve bir şey üzerinde çalışmayı planlıyorsanız, lütfen ilgili konu hakkında yorum yapın veya önce yeni bir sorun oluşturun. Bu şekilde değerli çalışmalarınızın boşuna olmamasını sağlayabiliriz. + +Since Flarum is so extension-driven, we highly recommend [our extension docs](extend/README.md) as a reference when working on core, as well as for bundled extensions. You should start with [the introduction](extend/README.md) for a better understanding of our extension philosophy. + +## Geliştirme İş Akışı + +### Setting Up a Local Codebase + +[flarum/flarum](https://github.com/flarum/flarum) is a "skeleton" application which uses Composer to download the core package and a bunch of extensions. Source code for Flarum core, extensions, and all packages used by the aforementioned is located in the Flarum monorepo [flarum/framework](https://github.com/flarum/framework). In order to contribute to these, you'll need to fork and clone the monorepo repository locally, and then add it to your dev environment as a [Composer path repository](https://getcomposer.org/doc/05-repositories.md#path): + +```bash +git clone https://github.com/flarum/flarum.git +cd flarum + +# Or, when you want to clone directly into the current directory +git clone https://github.com/flarum/flarum.git . +# Note, the directory must be empty + +# Set up a Composer path repository for Flarum monorepo packages +composer config repositories.0 path "PATH_TO_MONOREPO/*/*" +git clone https://github.com//framework.git PATH_TO_MONOREPO +``` + +Tipik bir katkı iş akışı şuna benzer: + +Son olarak, kurulumu dizin havuzlarından tamamlamak için `composer install` çalıştırın. + +Yerel kurulumunuz kurulduktan sonra, **config.php** içinde `debug` modunu etkinleştirdiğinizden ve php yapılandırmanızda `display_errors` u `On` olarak ayarladığınızdan emin olun. Bu, hem Flarum hem de PHP için hata ayrıntılarını görmenize olanak sağlar. Debug mode also forces a re-compilation of Flarum's asset files on each request, removing the need to call `php flarum cache:clear` after each change to the extension's JavaScript or CSS. + +Flarum'un ön uç kodu ES6'da yazılır ve JavaScript'e aktarılır. During development you will need to recompile the JavaScript using [Node.js](https://nodejs.org/) and [`yarn`](https://yarnpkg.com/). **Please do not commit the resulting `dist` files when sending PRs**; this is automatically taken care of when changes are merged into the `main` branch. + +To contribute to the frontend, first install the JavaScript dependencies. The monorepo uses [yarn workspaces](https://classic.yarnpkg.com/lang/en/docs/workspaces/) to easily install JS dependencies across all packages within. + +```bash +cd packages/framework +yarn install +``` + +Daha sonra geliştirme sırasındaki değişiklikler için JavaScript dosyalarını izleyebilirsiniz: + +```bash +cd framework/core/js +yarn dev +``` + +Uzantılar için de süreç aynıdır. + +```bash +cd extensions/tags/js +yarn de +``` + +### Geliştirme araçları + +Üzerinde çalışacağınız depoları çatallayıp klonladıktan sonra, değişikliklerinizi test edebilmeniz için yerel barındırma kurmanız gerekecektir. Flarum şu anda bir geliştirme sunucusuyla birlikte gelmiyor, dolayısıyla bu yerel Flarum kurulumuna hizmet etmek için Apache/NGINX/Caddy/etc'yi kurmanız gerekecek. + +Alternatif olarak, bir hizmet sunmak için [Laravel Valet](https://laravel.com/docs/master/valet) (Mac), [XAMPP](https://www.apachefriends.org/index.html) (Windows) veya [Docker-Flarum](https://github.com/mondediefr/docker-flarum) (Linux) gibi araçları kullanabilirsiniz. yerel forum. + +Flarum'a katkıda bulunanların çoğu [PHPStorm](https://www.jetbrains.com/phpstorm/download/) veya [Visual Studio Code](https://code.visualstudio.com/) ile geliştirir. + +## Kodlama Stili + +A typical contribution workflow looks like this: + +0. 🌳 Uygun **dalı** yeni bir özellik dalına ayırın. + * *Hata düzeltmeleri* en son kararlı dala gönderilmelidir. + * Mevcut Flarum sürümüyle geriye dönük olarak tamamen uyumlu olan *Küçük* özellikler, en son kararlı dala gönderilebilir. + +1. 🔨 Bir **kod** yazın. + * [Kodlama Stili](#Kodlama-Stili) hakkında aşağıya bakın. + * *Ana* özellikler her zaman gelecek Flarum sürümünü içeren "ana" şubeye gönderilmelidir. + * *Major* features should always be sent to the `main` branch, which contains the upcoming Flarum release. + * Dahili olarak `/` (eg. `tz/refactor-frontend`) adlandırma şemasını kullanıyoruz. + +2. 🚦 **Kodunuzu** test edin. + * Hataları giderirken veya özellikler eklerken gerektiği gibi birim testleri ekleyin. + +3. 💾 Kodunuzu açıklayıcı bir mesajla **işleyin**. + * Add unit tests as necessary when fixing bugs or adding features. + * Test paketini ilgili paket klasöründeki `vendor/bin/phpunit` ile çalıştırın. + * See [here](extend/testing.md) for more information about testing in Flarum. + +4. 🎁 GitHub'da bir Çekme İsteği (PR) **gönderin**. + * Değişikliğiniz mevcut bir sorunu çözüyorsa (genellikle bu, 123 numaralı sorun numarası olmak üzere yeni satırda "123 numaralı düzeltmeleri" içermelidir). + * [Geleneksel Taahhütler](https://www.conventionalcommits.org/en/v1.0.0/#summary) spesifikasyonunu izleyin. + * *Fix* commits should describe the issue fixed, not how it was fixed. + +5. 🤝 Onay için Flarum ekibiyle **iletişim kurun**. + * Çekme talebi şablonunu doldurun. + * Değişikliğiniz görselse, değişikliği gösteren bir ekran görüntüsü veya GIF ekleyin. + * JavaScript `dist` dosyalarını DERLEMEYİN. Bunlar birleştirme sırasında otomatik olarak derlenecektir. + +6. 🕺 **Dans et** tıpkı Flarum'a katkıda bulunduğun gibi. + * Ekip üyeleri kodunuzu inceleyecek. Bazı değişiklikler veya iyileştirmeler veya alternatifler önerebiliriz, ancak küçük değişiklikler için çekme talebinizin hızla kabul edilmesi gerekir. + * Geri bildirimi ele alırken, üzerine yazmak veya ezmek yerine ek taahhütleri itin (birleştireceğiz). + +7. 🕺 **Dance** like you just contributed to Flarum. + +## Geliştirme araçları + +In order to keep the Flarum codebase clean and consistent, we have a number of coding style guidelines that we follow. When in doubt, read the source code. + +Don't worry if your code styling isn't perfect! StyleCI and Prettier will automatically check formatting for every pull request. This allows us to focus on the content of the contribution, not the code style. + +### PHP + +Flarum follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) coding standard and the [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) autoloading standard. On top of this, we conform to a number of [other style rules](https://github.com/flarum/framework/blob/main/.styleci.yml). We use PHP 7 type hinting and return type declarations where possible, and [PHPDoc](https://docs.phpdoc.org/) to provide inline documentation. Try and mimic the style used by the rest of the codebase in your contributions. + +* `Flarum\Discussion`, not `Flarum\Discussions`) +* Arayüzlerin sonuna `Interface` eklenmelidir (ör. `MailableInterface`) +* Abstract sınıflarının önüne `Abstract` yazılmalıdır (ör `AbstractModel`) +* Özelliklerin sonuna `Trait` eklenmelidir (ör. `ScopeVisibilityTrait`) + +### JavaScript + +Flarum's JavaScript mostly follows the [Airbnb Style Guide](https://github.com/airbnb/javascript). We use [ESDoc](https://esdoc.org/manual/tags.html) to provide inline documentation. + +### Çeviriler + +**Columns** should be named according to their data type: +* DATETIME veya TIMESTAMP: `{verbed}_at` (ör. created_at, read_at) veya `{verbed}_until` (ör. suspended_until) +* INT bu bir sayıdır: `{noun}_count` (ör. comment_count, word_count) +* Yabancı anahtar: `{verbed}_{entity}_id` (ör. hidden_user_id) + * Fiil birincil ilişki için ihmal edilebilir (ör. Yazının yazarı sadece `user_id`) +* BOOL: `is_{adjective}` (ör. is_locked) + +**Tables** should be named as follows: +* Çoğul biçim kullanın (`discussions`) +* Birden çok kelimeyi alt çizgilerle ayırın (`access_tokens`) +* İlişki tabloları için, iki tablo adını alfabetik sırayla bir alt çizgi ile tekil biçimde birleştirin (ör. `discussion_user`) + +### CSS + +Flarum's CSS classes roughly follow the [SUIT CSS naming conventions](https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md) using the format `.ComponentName-descendentName--modifierName`. + +### Çeviriler + +We use a [standard key format](/extend/i18n.md#appendix-a-standard-key-format) to name translation keys descriptively and consistently. + +## Katılımcı Lisans Sözleşmesi + +By contributing your code to Flarum you grant the Flarum Foundation (Stichting Flarum) a non-exclusive, irrevocable, worldwide, royalty-free, sublicensable, transferable license under all of Your relevant intellectual property rights (including copyright, patent, and any other rights), to use, copy, prepare derivative works of, distribute and publicly perform and display the Contributions on any licensing terms, including without limitation: (a) open source licenses like the MIT license; and (b) binary, proprietary, or commercial licenses. Except for the licenses granted herein, You reserve all right, title, and interest in and to the Contribution. + +You confirm that you are able to grant us these rights. You represent that You are legally entitled to grant the above license. If Your employer has rights to intellectual property that You create, You represent that You have received permission to make the Contributions on behalf of that employer, or that Your employer has waived such rights for the Contributions. + +You represent that the Contributions are Your original works of authorship, and to Your knowledge, no other person claims, or has the right to claim, any right in any invention or patent related to the Contributions. You also represent that You are not legally obligated, whether by entering into an agreement or otherwise, in any way that conflicts with the terms of this license. + +The Flarum Foundation acknowledges that, except as explicitly described in this Agreement, any Contribution which you provide is on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. \ No newline at end of file diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/current.json b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/current.json new file mode 100644 index 000000000..cc8d5bdce --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/current.json @@ -0,0 +1,42 @@ +{ + "version.label": { + "message": "Next", + "description": "The label for version current" + }, + "sidebar.guideSidebar.category.Introduction": { + "message": "Giriş", + "description": "The label for category Introduction in sidebar guideSidebar" + }, + "sidebar.guideSidebar.category.Setting Up": { + "message": "Ayarlama", + "description": "The label for category Setting Up in sidebar guideSidebar" + }, + "sidebar.guideSidebar.category.Management": { + "message": "Yönetim", + "description": "The label for category Management in sidebar guideSidebar" + }, + "sidebar.guideSidebar.category.Advanced": { + "message": "Advanced", + "description": "The label for category Advanced in sidebar guideSidebar" + }, + "sidebar.extendSidebar.category.Main Concepts": { + "message": "Ana Kavramlar", + "description": "The label for category Main Concepts in sidebar extendSidebar" + }, + "sidebar.extendSidebar.category.Reference Guides": { + "message": "Referans Kılavuzları", + "description": "The label for category Reference Guides in sidebar extendSidebar" + }, + "sidebar.extendSidebar.category.Advanced Guides": { + "message": "Gelişmiş Kılavuzlar", + "description": "The label for category Advanced Guides in sidebar extendSidebar" + }, + "sidebar.extendSidebar.category.Update Guides": { + "message": "Update Guides", + "description": "The label for category Update Guides in sidebar extendSidebar" + }, + "sidebar.internalSidebar.category.Internal Docs": { + "message": "Internal Docs", + "description": "The label for category Internal Docs in sidebar internalSidebar" + } +} \ No newline at end of file diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/README.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/README.md new file mode 100644 index 000000000..78328a2ea --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/README.md @@ -0,0 +1,40 @@ +- - - +slug: /extend +- - - + +# Flarum'u Genişletmek + +Flarum minimalisttir, ancak aynı zamanda oldukça genişletilebilir. Aslında, Flarum ile birlikte gelen özelliklerin çoğu aslında uzantılardır! + +This approach makes Flarum extremely customizable. A user can disable any features they don't use on their forum, and install other extensions to make a forum perfect for their community. + +In order to achieve this extensibility, Flarum has been built with rich APIs and extension points. With some programming knowledge, you can leverage these APIs to add just about any feature you want. This section of the documentation aims to teach you how Flarum works, and how to use the APIs so that you can build your own extensions. + +## Çekirdek ve Uzantılar + +Where do we draw the line between Flarum's core and its extensions? Why are some features included in the core, and others aren't? It is important to understand this distinction so that we can maintain consistency and quality within Flarum's ecosystem. + +**Flarum's core** is not intended to be packed full of features. Rather, it is a scaffold, or a framework, which provides a reliable foundation on which extensions can build. It contains only basic, unopinionated functionality that is essential to a forum: discussions, posts, users, groups, and notifications. + +**Bundled extensions** are features that are packaged with Flarum and enabled by default. They are extensions just like any other, and may be disabled and uninstalled. While their scope is not intended to address all use-cases, the idea is to make them generic and configurable enough that they can satisfy the majority. + +**Third-party extensions** are features which are made by others and are not officially supported by the Flarum team. They can be built and used to address more specific use-cases. + +If you are aiming to address a bug or shortcoming of the core, or of an existing bundled extension, it may be appropriate to *contribute to the respective project* rather than disperse effort on a new third-party extension. It is a good idea to start a discussion on the [Flarum Community](https://discuss.flarum.org/) to get the perspective of the Flarum developers. + +## Yararlı Kaynaklar + +- [Bu Belge](start.md) +- [Tips for Beginning Developers](https://discuss.flarum.org/d/5512-extension-development-tips) +- [Flarum CLI](https://github.com/flarum/cli) +- [Developers explaining their workflow for extension development](https://discuss.flarum.org/d/6320-extension-developers-show-us-your-workflow) +- [Extension namespace tips](https://discuss.flarum.org/d/9625-flarum-extension-namespacing-tips) +- [Mithril js documentation](https://mithril.js.org/) +- [Laravel API Dokümanları](https://laravel.com/api/8.x/) +- [Flarum API Dokümanları](https://api.flarum.org) +- [ES6 cheatsheet](https://github.com/DrkSephy/es6-cheatsheet) + +### Flarum Genişletme + +- [Official Flarum Dev Community](https://discuss.flarum.org/t/dev) +- [Join us on #extend in our discord chat](https://flarum.org/discord/) diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/admin.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/admin.md new file mode 100644 index 000000000..6cb877127 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/admin.md @@ -0,0 +1,214 @@ +# Yönetici Gösterge Tablosu + +Beta 15, tamamen yeniden tasarlanmış bir yönetici paneli ve frontend API'sini tanıttı. Uzantınıza ayar veya izin eklemek artık her zamankinden daha kolay. + +Beta 15'ten önce, uzantı ayarları ya bir `SettingsModal`'a ekleniyordu ya da daha karmaşık ayarlar için yeni bir sayfa ekleniyordu. Artık her uzantının bilgileri, ayarları ve uzantının kendi izinlerini içeren bir sayfası var. + +Ayarları kolayca kaydedebilir, temel [`Uzantı Sayfası`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) genişletebilir veya kendi tamamen özel sayfanızı sağlayabilirsiniz. + +## Uzantı Veri API'si + +Bu yeni API, çok az kod satırıyla uzantınıza ayarlar eklemenizi sağlar. + +### Telling the API about your extension + +Before you can register anything, you need to tell `ExtensionData` what extension it is about to get data for. + +Simply run the `for` function on `app.extensionData` passing in the id of your extension. To find you extension id, take the composer name and replace any slashes with dashes (example: 'fof/merge-discussions' becomes 'fof-merge-discussions'). Extensions with the `flarum-` and `flarum-ext-` will omit those from the name (example: 'webbinaro/flarum-calendar' becomes 'webbinaro-calendar'). + +For the following example, we will use the fictitious extension 'acme/interstellar': + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') +}); +``` + +Once that is done, you can begin adding settings and permissions. + +:::tip Note + +All registration functions on `ExtensionData` are chainable, meaning you can call them one after another without running `for` again. + +::: + +### Registering Settings + +Adding settings fields in this way is recommended for simple items. As a rule of thumb, if you only need to store things in the settings table, this should be enough for you. + +To add a field, call the `registerSetting` function after `for` on `app.extensionData` and pass a 'setting object' as the first argument. Behind the scenes `ExtensionData` actually turns your settings into an [`ItemList`](https://api.docs.flarum.org/js/master/class/src/common/utils/itemlist.ts~itemlist), you can pass a priority number as the second argument. + +Here's an example with a switch (boolean) item: + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerSetting( + { + setting: 'acme-interstellar.coordinates', // This is the key the settings will be saved under in the settings table in the database. + label: app.translator.trans('acme-interstellar.admin.coordinates_label'), // The label to be shown letting the admin know what the setting does. + help: app.translator.trans('acme-interstellar.admin.coordinates_help'), // Optional help text where a longer explanation of the setting can go. + type: 'boolean', // What type of setting this is, valid options are: boolean, text (or any other tag type), and select. + }, + 30 // Optional: Priority + ) +}); +``` + +If you use `type: 'select'` the setting object looks a little bit different: + +```js +{ + setting: 'acme-interstellar.fuel_type', + label: app.translator.trans('acme-interstellar.admin.fuel_type_label'), + type: 'select', + options: { + 'LOH': 'Liquid Fuel', // The key in this object is what the setting will be stored as in the database, the value is the label the admin will see (remember to use translations if they make sense in your context). + 'RDX': 'Solid Fuel', + }, + default: 'LOH', +} +``` + +Also, note that additional items in the setting object will be used as component attrs. This can be used for placeholders, min/max restrictions, etc: + +```js +{ + setting: 'acme-interstellar.crew_count', + label: app.translator.trans('acme-interstellar.admin.crew_count_label'), + type: 'number', + min: 1, + max: 10 +} +``` + +If you want to add something to the settings like some extra text or a more complicated input, you can also pass a callback as the first argument that returns JSX. This callback will be executed in the context of [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) and setting values will not be automatically serialized. + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerSetting(function () { + if (app.session.user.username() === 'RocketMan') { + + return ( +
+

{app.translator.trans('acme-interstellar.admin.you_are_rocket_man_label')}

+ +
+ ); + } + }) +}); +``` + +### Registering Permissions + +New in beta 15, permissions can now be found in 2 places. Now, you can view each extension's individual permissions on their page. All permissions can still be found on the permissions page. + +In order for that to happen, permissions must be registered with `ExtensionData`. This is done in a similar way to settings, call `registerPermission`. + +Arguments: + * Permission object + * What type of permission - see [`PermissionGrid`](https://api.docs.flarum.org/js/master/class/src/admin/components/permissiongrid.js~permissiongrid)'s functions for types (remove items from the name) + * `ItemList` priority + +Back to our favorite rocket extension: + +```js +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerPermission( + { + icon: 'fas fa-rocket', // Font-Awesome Icon + label: app.translator.trans('acme-interstellar.admin.permissions.fly_rockets_label'), // Permission Label + permission: 'discussion.rocket_fly', // Actual permission name stored in database (and used when checking permission). + tagScoped: true, // Whether it be possible to apply this permission on tags, not just globally. Explained in the next paragraph. + }, + 'start', // Category permission will be added to on the grid + 95 // Optional: Priority + ); +}); +``` + +If your extension interacts with the [tags extension](https://github.com/flarum/tags) (which is fairly common), you might want a permission to be tag scopable (i.e. applied on the tag level, not just globally). You can do this by including a `tagScoped` attribute, as seen above. Permissions starting with `discussion.` will automatically be tag scoped unless `tagScoped: false` is indicated. + +To learn more about Flarum permissions, see [the relevant docs](permissions.md). + +### Chaining Reminder + +Remember these functions can all be chained like: + +```js +app.extensionData + .for('acme-interstellar') + .registerSetting(...) + .registerSetting(...) + .registerPermission(...) + .registerPermission(...); +``` + +### Extending/Overriding the Default Page + +Sometimes you have more complicated settings that mess with relationships, or just want the page to look completely different. In this case, you will need to tell `ExtensionData` that you want to provide your own page. Note that `buildSettingComponent`, the util used to register settings by providing a descriptive object, is available as a method on `ExtensionPage` (extending from `AdminPage`, which is a generic base for all admin pages with some util methods). + +Create a new class that extends the `Page` or `ExtensionPage` component: + +```js +import ExtensionPage from 'flarum/admin/components/ExtensionPage'; + +export default class StarPage extends ExtensionPage { + content() { + return ( +

Hello from the settings section!

+ ) + } +} + +``` + +Then, simply run `registerPage`: + +```js + +import StarPage from './components/StarPage'; + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerPage(StarPage); +}); +``` + +This page will be shown instead of the default. + +You can extend the [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) or extend the base `Page` and design your own! + +## Composer.json Metadata + +In beta 15, extension pages make room for extra info which is pulled from extensions' composer.json. + +For more information, see the [composer.json schema](https://getcomposer.org/doc/04-schema.md). + +| Description | Where in composer.json | +| ---------------------------------- | ------------------------------------------------------------ | +| discuss.flarum.org discussion link | "forum" key inside "support" | +| Documentation | "docs" key inside "support" | +| Support (email) | "email" key inside "support" | +| Website | "homepage" key | +| Donate | "funding" key block (Note: Only the first link will be used) | +| Source | "source" key inside "support" | diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md new file mode 100644 index 000000000..cb9be17e7 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md @@ -0,0 +1,58 @@ +# API Azaltma + +Flarum comes with a builtin `Flarum\Api\Middleware\ThrottleApi` [middleware](middleware.md) for throttling requests to the API. This runs on every API route, and extensions can add their own custom logic to throttle requests. + +:::caution Forum Routes + +Some forum routes (login, register, forgot password, etc) work by calling an API route under the surface. The `ThrottleApi` middleware does not currently run for these requests, but that is planned for the future. + +::: + +## Custom Throttlers + +The format for a custom throttler is extremely simple: all you need is a closure or invokable class that takes the current request as an argument, and returns one of: + +- `false`: This explicitly bypasses throttling for this request, overriding all other throttlers +- `true`: This marks the request as to be throttled. +- `null`: This means that this throttler doesn't apply. Any other outputs will be ignored, with the same effect as `null`. + +Throttlers will be run on EVERY request, and are responsible for figuring out whether or not they apply. For example, consider Flarum's post throttler: + +```php +use DateTime; +use Flarum\Post\Post; + +function ($request) { + if (! in_array($request->getAttribute('routeName'), ['discussions.create', 'posts.create'])) { + return; + } + + $actor = $request->getAttribute('actor'); + + if ($actor->can('postWithoutThrottle')) { + return false; + } + + if (Post::where('user_id', $actor->id)->where('created_at', '>=', new DateTime('-10 seconds'))->exists()) { + return true; + } +}; +``` + +Throttlers can be added or removed via the `ThrottleApi` middleware in `extend.php`. For example: + +```php +set('throttleAll', function () { + return false; + }) + ->remove('bypassThrottlingAttribute'), + // Other extenders +]; +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/api.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/api.md new file mode 100644 index 000000000..200a2f954 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/api.md @@ -0,0 +1,353 @@ +# API and Data Flow + +In the [previous article](models.md), we learned how Flarum uses models to interact with data. Here, we'll learn how to get that data from the database to the JSON-API to the frontend, and all the way back again. + +:::bilgi + +To use the built-in REST API as part of an integration, see [Consuming the REST API](../rest-api.md). + +::: + +## API Request Lifecycle + +Before we go into detail about how to extend Flarum's data API, it's worth thinking about the lifecycle of a typical API request: + +![Flarum API Flowchart](/en/img/api_flowchart.png) + +1. An HTTP request is sent to Flarum's API. Typically, this will come from the Flarum frontend, but external programs can also interact with the API. Flarum's API mostly follows the [JSON:API](https://jsonapi.org/) specification, so accordingly, requests should follow [said specification](https://jsonapi.org/format/#fetching). +2. The request is run through [middleware](middleware.md), and routed to the proper controller. You can learn more about controllers as a whole on our [routes and content documentation](routes.md). Assuming the request is to the API (which is the case for this section), the controller that handles the request will be a subclass of `Flarum\Api\AbstractSerializeController`. +3. Any modifications done by extensions to the controller via the [`ApiController` extender](#extending-api-controllers) are applied. This could entail changing sort, adding includes, changing the serializer, etc. +4. The `$this->data()` method of the controller is called, yielding some raw data that should be returned to the client. Typically, this data will take the form of a Laravel Eloquent model collection or instance, which has been retrieved from the database. That being said, the data could be anything as long as the controller's serializer can process it. Each controller is responsible for implementing its own `data` method. Note that for `PATCH`, `POST`, and `DELETE` requests, `data` will perform the operation in question, and return the modified model instance. +5. That data is run through any pre-serialization callbacks that extensions register via the [`ApiController` extender](#extending-api-controllers). +6. The data is passed through a [serializer](#serializers), which converts it from the backend, database-friendly format to the JSON:API format expected by the frontend. It also attaches any related objects, which are run through their own serializers. As we'll explain below, extensions can [add / override relationships and attributes](#attributes-and-relationships) at the serialization level. +7. The serialized data is returned as a JSON response to the frontend. +8. If the request originated via the Flarum frontend's `Store`, the returned data (including any related objects) will be stored as [frontend models](#frontend-models) in the frontend store. + +## API Endpoints + +We learned how to use models to interact with data, but we still need to get that data from the backend to the frontend. We do this by writing API Controller [routes](routes.md), which implement logic for API endpoints. + +As per the JSON:API convention, we'll want to add separate endpoints for each operation we support. Common operations are: + +- Listing instances of a model (possibly including searching/filtering) +- Getting a single model instance +- Creating a model instance +- Updating a model instance +- Deleting a single model instance + +We'll go over each type of controller shortly, but once they're written, you can add these five standard endpoints (or a subset of them) using the `Routes` extender: + +```php + (new Extend\Routes('api')) + ->get('/tags', 'tags.index', ListTagsController::class) + ->get('/tags/{id}', 'tags.show', ShowTagController::class) + ->post('/tags', 'tags.create', CreateTagController::class) + ->patch('/tags/{id}', 'tags.update', UpdateTagController::class) + ->delete('/tags/{id}', 'tags.delete', DeleteTagController::class) +``` + +:::caution + +Paths to API endpoints are not arbitrary! To support interactions with frontend models: + +- The path should either be `/prefix/{id}` for get/update/delete, or `/prefix` for list/create. +- the prefix (`tags` in the example above) must correspond to the JSON:API model type. You'll also use this model type in your serializer's `$type` attribute, and when registering the frontend model (`app.store.models.TYPE = MODEL_CLASS`). +- The methods must match the example above. + +Also, remember that route names (`tags.index`, `tags.show`, etc) must be unique! + +::: + +The `Flarum\Api\Controller` namespace contains a number of abstract controller classes that you can extend to easily implement your JSON-API resources. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically create your endpoint controllers: +```bash +$ flarum-cli make backend api-controller +``` + +::: + +### Listing Resources + +For the controller that lists your resource, extend the `Flarum\Api\Controller\AbstractListController` class. At a minimum, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a collection of models. The `data` method accepts the `Request` object and the tobscure/json-api `Document`. + +```php +use Flarum\Api\Controller\AbstractListController; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ListTagsController extends AbstractListController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + return Tag::all(); + } +} +``` + +#### Pagination + +You can allow the number of resources being **listed** to be customized by specifying the `limit` and `maxLimit` properties on your controller: + +```php + // The number of records included by default. + public $limit = 20; + + // The maximum number of records that can be requested. + public $maxLimit = 50; +``` + +You can then extract pagination information from the request using the `extractLimit` and `extractOffset` methods: + +```php +$limit = $this->extractLimit($request); +$offset = $this->extractOffset($request); + +return Tag::skip($offset)->take($limit); +``` + +To add pagination links to the JSON:API document, use the `Document::addPaginationLinks` method. + +#### Sorting + +You can allow the sort order of resources being **listed** to be customized by specifying the `sort` and `sortField` properties on your controller: + +```php + // The default sort field and order to use. + public $sort = ['name' => 'asc']; + + // The fields that are available to be sorted by. + public $sortFields = ['firstName', 'lastName']; +``` + +You can then extract sorting information from the request using the `extractSort` method. This will return an array of sort criteria which you can apply to your query: + +```php +use Illuminate\Support\Str; + +// ... + +$sort = $this->extractSort($request); +$query = Tag::query(); + +foreach ($sort as $field => $order) { + $query->orderBy(Str::snake($field), $order); +} + +return $query->get(); +``` + +#### Arama + +Read our [searching and filtering](search.md) guide for more information! + +### Showing a Resource + +For the controller that shows a single resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the list controller, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a single model. We'll learn about serializers [in just a bit](#serializers). + +```php +use Flarum\Api\Controller\AbstractShowController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ShowTagController extends AbstractShowController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + return Tag::findOrFail($id); + } +} +``` + +### Creating a Resource + +For the controller that creates a resource, extend the `Flarum\Api\Controller\AbstractCreateController` class. This is the same as the show controller, except the response status code will automatically be set to `201 Created`. You can access the incoming JSON:API document body via `$request->getParsedBody()`: + +```php +use Flarum\Api\Controller\AbstractCreateController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class CreateTagController extends AbstractCreateController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $attributes = Arr::get($request->getParsedBody(), 'data.attributes'); + + return Tag::create([ + 'name' => Arr::get($attributes, 'name') + ]); + } +} +``` + +### Updating a Resource + +For the controller that updates a resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the create controller, you can access the incoming JSON:API document body via `$request->getParsedBody()`. + +### Deleting a Resource + +For the controller that deletes a resource, extend the `Flarum\Api\Controller\AbstractDeleteController` class. You only need to implement a `delete` method which enacts the deletion. The controller will automatically return an empty `204 No Content` response. + +```php +use Flarum\Api\Controller\AbstractDeleteController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; + +class DeleteTagController extends AbstractDeleteController +{ + protected function delete(Request $request) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + Tag::findOrFail($id)->delete(); + } +} +``` + +### Including Relationships + +To include relationships when **listing**, **showing**, or **creating** your resource, specify them in the `$include` and `$optionalInclude` properties on your controller: + +```php + // The relationships that are included by default. + public $include = ['user']; + + // Other relationships that are available to be included. + public $optionalInclude = ['discussions']; +``` + +You can then get a list of included relationships using the `extractInclude` method. This can be used to eager-load the relationships on your models before they are serialized: + +```php +$relations = $this->extractInclude($request); + +return Tag::all()->load($relations); +``` + +### Extending API Controllers + +It is possible to customize all of these options on _existing_ API controllers too via the `ApiController` extender + +```php +use Flarum\Api\Event\WillGetData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->setSerializer(MyDiscussionSerializer::class) + ->addInclude('user') + ->addOptionalInclude('posts') + ->setLimit(20) + ->setMaxLimit(50) + ->setSort(['name' => 'asc']) + ->addSortField('firstName') + ->prepareDataQuery(function ($controller) { + // Add custom logic here to modify the controller + // before data queries are executed. + }) +] +``` + +The `ApiController` extender can also be used to adjust data before serialization + +```php +use Flarum\Api\Event\WillSerializeData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->prepareDataForSerialization(function ($controller, $data, $request, $document) { + $data->load('myCustomRelation'); + }), +] +``` + +## Serializers + +Before we can send our data to the frontend, we need to convert it to JSON:API format so that it can be consumed by the frontend. You should become familiar with the [JSON:API specification](https://jsonapi.org/format/). Flarum's JSON:API layer is powered by the [tobscure/json-api](https://github.com/tobscure/json-api) library. + +A serializer is just a class that converts some data (usually [Eloquent models](models.md#backend-models)) into JSON:API. Serializers serve as intermediaries between backend and frontend models: see the [model documentation](models.md) for more information. To define a new resource type, create a new serializer class extending `Flarum\Api\Serializer\AbstractSerializer`. You must specify a resource `$type` and implement the `getDefaultAttributes` method which accepts the model instance as its only argument: + +```php +use Flarum\Api\Serializer\AbstractSerializer; +use Flarum\Api\Serializer\UserSerializer; + +class DiscussionSerializer extends AbstractSerializer +{ + protected $type = 'discussions'; + + protected function getDefaultAttributes($discussion) + { + return [ + 'title' => $discussion->title, + ]; + } +} +``` + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically create your serializer: +```bash +$ flarum-cli make backend api-serializer +``` + +::: + +### Attributes and Relationships + +You can also specify relationships for your resource. Simply create a new method with the same name as the relation on your model, and return a call to `hasOne` or `hasMany` depending on the nature of the relationship. You must pass in the model instance and the name of the serializer to use for the related resources. + +```php + protected function user($discussion) + { + return $this->hasOne($discussion, UserSerializer::class); + } +``` + +### Extending Serializers + +To add **attributes** and **relationships** to an existing resource type, use the `ApiSerializer` extender: + +```php +use Flarum\Api\Serializer\UserSerializer; + +return [ + (new Extend\ApiSerializer(UserSerializer::class)) + // One attribute at a time + ->attribute('firstName', function ($serializer, $user, $attributes) { + return $user->first_name + }) + // Multiple modifications at once, more complex logic + ->mutate(function($serializer, $user, $attributes) { + $attributes['someAttribute'] = $user->someAttribute; + if ($serializer->getActor()->can('administrate')) { + $attributes['someDate'] = $serializer->formatDate($user->some_date); + } + + return $attributes; + }) + // API relationships + ->hasOne('phone', PhoneSerializer::class) + ->hasMany('comments', CommentSerializer::class), +] +``` + +### Non-Model Serializers and `ForumSerializer` + +Serializers don't have to correspond to Eloquent models: you can define JSON:API resources for anything. For instance, Flarum core uses the [`Flarum\Api\Serializer\ForumSerializer`](https://api.docs.flarum.org/php/master/flarum/api/serializer/forumserializer) to send an initial payload to the frontend. This can include settings, whether the current user can perform certain actions, and other data. Many extensions add data to the payload by extending the attributes of `ForumSerializer`. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/assets.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/assets.md new file mode 100644 index 000000000..16b401fc3 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/assets.md @@ -0,0 +1,7 @@ +# Extension Assets + +Some extensions might want to include assets like images or JSON files in their source code (note that this is not the same as uploads, which would probably require a [filesystem disk](filesystem.md)). + +This is actually very easy to do. Just create an `assets` folder at the root of your extension, and place any asset files there. Flarum will then automatically copy those files to its own `assets` directory (or other storage location if [one is offered by extensions](filesystem.md)) every time the extension is enabled or [`php flarum assets:publish`](../console.md) is executed. + +If using the default storage driver, assets will be available at `https://FORUM_URL/assets/extensions/EXTENSION_ID/file.path`. However, since other extensions might use remote filesystems, we recommend serializing the url to assets you need in the backend. See [Flarum's serialization of the logo and favicon URLs](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Serializer/ForumSerializer.php#L85-L86) for an example. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md new file mode 100644 index 000000000..0ffc13bbb --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md @@ -0,0 +1,206 @@ +# Yetkilendirme + +As with any framework, Flarum allows certain actions and content to be restricted to certain users. There are 2 parallel systems for this: + +- The authorization process dictates whether a user can take a certain action. +- Visibility scoping can be applied to a database query to efficiently restrict the records that users can access. This is documented in our [model visibility](model-visibility.md) article. + +## Yetkilendirme Süreci + +The authorization process is used to check whether a person is allowed to perform certain actions. For instance, we want to check if a user is authorized before they: + +- Access the admin dashboard +- Start a discussion +- Edit a post +- Update another user's profile + +Each of these is determined by unique criteria: in some cases a flag is sufficient; otherwise, we might need custom logic. + +## Nasıl Çalışır + +Authorization queries are made with 3 parameters, with logic contained in [`Flarum\User\Gate`](https://api.docs.flarum.org/php/master/flarum/user/access/gate): + +1. The actor: the user attempting to perform the action +2. The ability: a string representing the action the actor is attempting +3. The arguments: usually an instance of a database model which is the subject of the attempted ability, but could be anything. + +First, we run the entire request (all three parameters) through all [policies](#policies) registered by extensions and core. Policies are blocks of logic provided by core and extensions that determine whether the actor can perform the ability on the arguments. Policies can return one of the following: + +- `Flarum\User\Access\AbstractPolicy::ALLOW` (via `$this->allow()`) +- `Flarum\User\Access\AbstractPolicy::DENY` (via `$this->deny()`) +- `Flarum\User\Access\AbstractPolicy::FORCE_ALLOW` (via `$this->forceAllow()`) +- `Flarum\User\Access\AbstractPolicy::FORCE_DENY` (via `$this->forceDeny()`) + +Policy results are considered in the priority `FORCE_DENY` > `FORCE_ALLOW` > `DENY` > `ALLOW`. For example, if a single policy returns `FORCE_DENY`, all other policies will be ignored. If one policy returns `DENY` and 10 policies return `ALLOW`, the request will be denied. This allows decisions to be made regardless of the order in which extensions are booted. Note that policies are extremely powerful: if access is denied at the policy stage, that will override group permissions and even admin privileges. + +Secondly, if all policies return null (or don't return anything), we check if the user is in a group that has a permission equal to the ability (note that both permissions and abilities are represented as strings). If so, we authorize the action. See our [Groups and Permissions documentation](permissions.md) for more information on permissions. + +Then, if the user is in the admin group, we will authorize the action. + +Finally, as we have exhausted all checks, we will assume that the user is unauthorized and deny the request. + +## Yetkilendirme Nasıl Kullanılır + +Flarum's authorization system is accessible through public methods of the `Flarum\User\User` class. The most important ones are listed below; others are documented in our [PHP API documentation](https://api.docs.flarum.org/php/master/flarum/user/user). + + +In this example, we will use `$actor` as an instance of `Flarum\User\User`, `'viewForum'` and `'reply'` as examples of abilities, and `$discussion` (instance of `Flarum\Discussion\Discussion`) as an example argument. + +```php +// Check whether a user can perform an action. +$canDoSomething = $actor->can('viewForum'); + +// Check whether a user can perform an action on a subject. +$canDoSomething = $actor->can('reply', $discussion); + +// Raise a PermissionDeniedException if a user cannot perform an action. +$actor->assertCan('viewForum'); +$actor->assertCan('reply', $discussion); + +// Raise a NotAuthenticatedException if the user is not logged in. +$actor->assertRegistered(); + +// Raise a PermissionDeniedException if the user is not an admin. +$actor->assertAdmin(); + +// Check whether one of the user's groups have a permission. +// WARNING: this should be used with caution, as it doesn't actually +// run through the authorization process, so it doesn't account for policies. +// It is, however, useful in implementing custom policies. +$actorHasPermission = $actor->hasPermission(`viewForum`); +``` + +## Özel Politikalar + +Policies allow us to use custom logic beyond simple groups and permissions when evaluating authorization for an ability with a subject. For instance: + +- We want to allow users to edit posts even if they aren't moderators, but only their own posts. +- Depending on settings, we might allow users to rename their own discussions indefinitely, for a short period of time after posting, or not at all. + +As described [above](#how-it-works), on any authorization check, we query all policies registered for the target's model, or any parent classes of the target's model. If no target is provided, any policies registered as `global` will be applied. + +So, how does a policy get "checked"? + +First, we check if the policy class has a method with the same name as the ability being evaluated. If so, we run it with the actor and subject as parameters. If that method returns a non-null value, we return that result. Otherwise, we continue to the next step (not necessarily the next policy). + +Then, we check if the policy class has a method called `can`. If so, we run it with the actor, ability, and subject, and return the result. + +If `can` doesn't exist or returns null, we are done with this policy, and we proceed to the next one. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate policies: +```bash +$ flarum-cli make backend policy +``` + +::: + +### Örnek Politikalar + +Let's take a look at an example policy from [Flarum Tags](https://github.com/flarum/tags/blob/master/src/Access): + +```php +is_restricted) { + return $actor->hasPermission('tag'.$tag->id.'.startDiscussion') ? $this->allow() : $this->deny(); + } + } + + /** + * @param User $actor + * @param Tag $tag + * @return bool|null + */ + public function addToDiscussion(User $actor, Tag $tag) + { + return $this->startDiscussion($actor, $tag); + } +} +``` + +We can also have global policies, which are run when `$user->can()` is called without a target model instance. Again from Tags: + +```php +settings = $settings; + } + + /** + * @param Flarum\User\User $actor + * @param string $ability + * @return bool|void + */ + public function can(User $actor, string $ability) + { + if (in_array($ability, ['viewForum', 'startDiscussion'])) { + $enoughPrimary = count(Tag::getIdsWhereCan($actor, $ability, true, false)) >= $this->settings->get('min_primary_tags'); + $enoughSecondary = count(Tag::getIdsWhereCan($actor, $ability, false, true)) >= $this->settings->get('min_secondary_tags'); + + if ($enoughPrimary && $enoughSecondary) { + return $this->allow(); + } else { + return $this->deny(); + } + } + } +} +``` + +### Kayıt Politikaları + +Both model-based and global policies can be registered with the `Policy` extender in your `extend.php` file: + +```php +use Flarum\Extend; +use Flarum\Tags\Tag; +use YourNamespace\Access; + +return [ + // Other extenders + (new Extend\Policy()) + ->modelPolicy(Tag::class, Access\TagPolicy::class) + ->globalPolicy(Access\GlobalPolicy::class), + // Other extenders +]; +``` + +## Ön Uç Yetkilendirmesi + +Commonly, you'll want to use authorization results in frontend logic. For example, if a user doesn't have permission to see search users, we shouldn't send requests to that endpoint. And if a user doesn't have permission to edit users, we shouldn't show menu items for that. + +Because we can't do authorization checks in the frontend, we have to perform them in the backend, and attach them to serialization of data we're sending. Global permissions (`viewForum`, `viewUserList`) can be included on the `ForumSerializer`, but for object-specific authorization, we may want to include those with the subject object. For instance, when we return lists of discussions, we check whether the user can reply, rename, edit, and delete them, and store that data on the frontend discussion model. It's then accessible via `discussion.canReply()` or `discussion.canEdit()`, but there's nothing magic there: it's just another attribute sent by the serializer. + +For an example of how to attach data to a serializer, see a [similar case for transmitting settings](settings.md#accessing-settings). diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md new file mode 100644 index 000000000..60b6f37f9 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md @@ -0,0 +1,172 @@ +# Arka Uç Etkinlikleri + +Often, an extension will want to react to some events occuring elsewhere in Flarum. For instance, we might want to increment a counter when a new discussion is posted, send a welcome email when a user logs in for the first time, or add tags to a discussion before saving it to the database. These events are known as **domain events**, and are broadcasted across the framework through [Laravel's event system](https://laravel.com/docs/8.x/events). + +For a full list of backend events, see our [API documentation](https://api.docs.flarum.org/php/master/search.html?search=Event). Domain events classes are organized by namespace, usually `Flarum\TYPE\Event`. + + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate event listeners: +```bash +$ flarum-cli make backend event-listener +``` + +::: + +## Etkinliği Dinlemek + +You can attach a listener to an event using the [`Event`](https://api.docs.flarum.org/php/master/flarum/extend/event) [extender](start.md#extenders): + +```php +use Flarum\Extend; +use Flarum\Post\Event\Deleted; +use Symfony\Contracts\Translation\TranslatorInterface; + + +return [ + (new Extend\Event) + ->listen(Deleted::class, function($event) { + // do something here + }) + ->listen(Deleted::class, PostDeletedListener::class) +]; +``` +```php +class PostDeletedListener +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function handle(Deleted $event) + { + // Your logic here + } +} +``` + +As shown above, a listener class can be used instead of a callback. This allows you to [inject dependencies](https://laravel.com/docs/8.x/container) into your listener class via constructor parameters. In this example we resolve a translator instance, but we can inject anything we want/need. + +You can also listen to multiple events at once via an event subscriber. This is useful for grouping common functionality; for instance, if you want to update some metadata on changes to posts: + +```php +use Flarum\Extend; +use Flarum\Post\Event\Deleted; +use Flarum\Post\Event\Saving; +use Symfony\Contracts\Translation\TranslatorInterface; + + +return [ + (new Extend\Event) + ->subscribe(PostEventSubscriber::class), +]; +``` +```php +class PostEventSubscriber +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function subscribe($events) + { + $events->listen(Deleted::class, [$this, 'handleDeleted']); + $events->listen(Saving::class, [$this, 'handleSaving']); + } + + public function handleDeleted(Deleted $event) + { + // Your logic here + } + + public function handleSaving(Saving $event) + { + // Your logic here + } +} +``` + +## Dispatching Events + +Dispatching events is very simple. All you need to do is inject `Illuminate\Contracts\Events\Dispatcher` into your class, and then call its `dispatch` method. For instance: + +```php +use Flarum\Post\Event\Deleted; +use Illuminate\Contracts\Events\Dispatcher; + + +class SomeClass +{ + /** + * @var Dispatcher + */ + protected $events; + + /** + * @param Dispatcher $events + */ + public function __construct(Dispatcher $events) + { + $this->events = $events; + } + + public function someMethod() + { + // Logic + $this->events->dispatch( + new Deleted($somePost, $someActor) + ); + // More Logic + } +} +``` + +## Özel Etkinlikler + +As an extension developer you can define your own events to allow yourself (or other extensions) to react to events in your extension. Events are generally instances of simple classes (no need to extend anything). When defining a new event, you'll typically want to use public properties, and maybe some methods for convenience of users. For example, if we take a look at `Flarum\Post\Event\Deleted`, it's just a wrapping around some data: + +```php +post = $post; + $this->actor = $actor; + } +} +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/cli.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/cli.md new file mode 100644 index 000000000..80e069bce --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/cli.md @@ -0,0 +1,15 @@ +# Flarum CLI + +The Flarum development ecosystem is oriented around many small, modules, interacting extensions. This is a very powerful and flexible paradigm, but it also brings the maintenance cost of creating and maintaining all these extensions. + +We've created the Flarum CLI (command line interface) as a tool to help developers by automating some repetitive and menial tasks, and allow them to get into the actual work without much hassle. + +Major updates about Flarum CLI will be published [on this discussion](https://discuss.flarum.org/d/28427-flarum-cli-v10). + +See the [package's readme](https://github.com/flarum/cli#readme) for information on: + +- Kurulum Belgeleri +- Usage +- Upgrading +- Available commands +- Some implementation details, if you're interested diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/console.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/console.md new file mode 100644 index 000000000..60c5cf3b8 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/console.md @@ -0,0 +1,70 @@ +# Konsol + +Flarum allows extension developers to add custom console commands in addition to the [default ones](../console.md) provided by flarum core. + +All console command development is done in the backend using PHP. To create a custom console command, you'll need to create a class that extends `\Flarum\Console\AbstractCommand`. + +```php +use Flarum\Console\AbstractCommand; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; + +class YourCommand extends AbstractCommand { + protected function configure() + { + $this + ->setName('YOUR COMMAND NAME') + ->setDescription('YOUR COMMAND DESCRIPTION'); + } + protected function fire() + { + // Your logic here! + } +} +``` + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate and register a console command: +```bash +$ flarum-cli make backend command +``` + +::: + +## Registering Console Commands + +To register console commands, use the `Flarum\Extend\Console` extender in your extension's `extend.php` file: + +```php +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; + +return [ + // Other extenders + (new Extend\Console())->command(CustomCommand::class) + // Other extenders +]; +``` + +## Scheduled Commands + +The `Flarum\Extend\Console`'s `schedule` method allows extension developers to create scheduled commands that run on an interval: + + +```php +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; +use Illuminate\Console\Scheduling\Event; + +return [ + // Other extenders + (new Extend\Console())->schedule('cache:clear', function (Event $event) { + $event->everyMinute(); + }, ['Arg1', '--option1', '--option2']), + // Other extenders +]; +``` + +In the callback provided as the second argument, you can call methods on the [$event object](https://laravel.com/api/8.x/Illuminate/Console/Scheduling/Event.html) to schedule on a variety of frequencies (or apply other options, such as only running on one server). See the [Laravel documentation](https://laravel.com/docs/8.x/scheduling#scheduling-artisan-commands) for more information. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/data.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/data.md new file mode 100644 index 000000000..b53e7c35c --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/data.md @@ -0,0 +1,3 @@ +# Verilerle Çalışma + +**Yakında Türkçe belgeler eklenecektir.** \ No newline at end of file diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md new file mode 100644 index 000000000..73058d3b1 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md @@ -0,0 +1,40 @@ +# Dağıtım + +You've written a great extension — and now you want the whole world to be able to use it. This document will take you through the process of distribution, from setting up a Git repository for your extension, to publishing it on Packagist. + +## Setting Up Git + +The first thing you'll need to do is set up a version control system (VCS). The most popular VCS is [Git](https://git-scm.com/). In this guide we'll be using Git, so make sure you have it [installed](https://git-scm.com/downloads) before continuing. If you don't have much Git knowledge, you may want to check out [these learning resources](https://try.github.io/). + +After you have installed Git, you'll need to initialize your repository. You can use `git init` on the command line if you're comfortable, or use a GUI tool like [SourceTree](https://www.sourcetreeapp.com/) or [GitKraken](https://www.gitkraken.com/). + +Then, you'll need an account in a Git hosting server, the most popular being [GitHub](https://github.com) and [GitLab](https://gitlab.com). These will instruct you on how to hook up your local repository with the online "remote" repository. + +## Tagging a Release + +As you are going to be publishing this extension, you'll want to make sure that the information is up to date. Take a minute to revisit `composer.json` and make sure package name, description, and Flarum extension information are all correct. It is recommended to have a `README.md` file in your repository to explain what the extension is, so create one if you haven't already. + +When you're ready to release, commit your extension's files to the repo and tag your first version: + +```bash +git tag v0.1.0 +git push && git push --tags +``` + +## Publishing on Packagist + +Composer packages are published to a Composer repository, usually [Packagist](https://packagist.org/). You will need an account to proceed. + +If this is the first release you are publishing of your extension, you will need to [submit your package](https://packagist.org/packages/submit) using its public repository URL. If your extension is located on GitHub, this URL will look something like `https://github.com/AUTHOR/NAME.git`. + +### Future Releases + +You can set up Packagist to [auto-update packages](https://packagist.org/about#how-to-update-packages). Then for future releases, all you will need to do with Git is commit, tag, and push it to the remote server. + +## Promoting Your Extension + +You will most likely want to create a discussion on the Flarum Community in the [Extensions tag](https://discuss.flarum.org/t/extensions). Other people can install your extension using the following command: + +```bash +composer require vendor/package +``` \ No newline at end of file diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md new file mode 100644 index 000000000..7a8db4f8c --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md @@ -0,0 +1,122 @@ +# Extending Extensions + +Flarum extensions aren't just for adding features to core: extensions can extend other extensions! + +:::tip + +To learn how to make your extension extensible, see the [relevant documentation](extensibility.md) + +::: + +## Dependencies + +If your extension relies on another extension, you'll want to ensure that: + +- The other extension is installed and enabled before yours can be. +- The other extension can't be disabled while yours is enabled. +- The other extension is booted before your extension. + +Flarum makes this very easy: just add the other extension to your extension's `composer.json`'s `require` section. + +For example, if you were building a new theme for the Flarum Tags extension, your `composer.json` would look like this: + +```json +{ + // ... + "require": { + "flarum/core": "^0.1.0-beta.15", // Since all extensions need to require core. + "flarum/tags": "^0.1.0-beta.15" // This tells Flarum to treat tags as a dependency of your extension. + }, + // ... +} +``` + +## Optional Dependencies + +Sometimes, extension A might want to extend extension B only if extension B is enabled. In this case, we call B an "Optional Dependency" of A. For instance, a drafts extension might want to add support for saving private discussion drafts, but only if the private discussion extension is enabled. + +The first step here is detecting whether extension B is enabled. In the frontend, this is easy: if extension B does anything in the frontend, its extension ID will appear as a key in the `flarum.extensions` global object. For instance: + +```js +if ('some-extension-id' in flarum.extensions) { + // do something +} +``` + +In the backend, you'll need to inject an instance of `Flarum\Extension\ExtensionManager`, and use its `isEnabled()` method. For instance: + +```php +extensions = $extensions; + } + + public function someMethod() + { + if ($this->extensions->isEnabled('some-extension-id')) { + // do something. + } + } +} +``` + +Generally, if your extension has optional dependencies, you'll want it to be booted after said optional dependencies. You can also do this by specifying composer package names (NOT flarum extension IDs) in an array for the `extra.flarum-extension.optional-dependencies` key of your composer.json. + +For instance: + +```json +{ + // ... + "extra": { + "flarum-extension": { + "optional-dependencies": [ + "flarum/tags" + ] + } + }, + // ... +} +``` + +## Importing from Extensions + +In the backend, you can import the classes you need via regular PHP `use` statements: + +```php + { + // Your Extension Code Here +}) + +export { + // Put all the stuff you want to export here. +} +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md new file mode 100644 index 000000000..ef202b2c7 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md @@ -0,0 +1,129 @@ +# Filesystem + +Flarum core integrates with the filesystem to store and serve assets (like compiled JS/CSS or upload logos/favicons) and avatars. + +Extensions can use Flarum's provided utils for their own filesystem interaction and file storage needs. This system is based around [Laravel's filesystem tools](https://laravel.com/docs/8.x/filesystem), which are in turn based on the [Flysystem library](https://github.com/thephpleague/flysystem). + +## Disks + +Filesystem **disks** represent storage locations, and are backed by storage drivers, which we'll cover later. Flarum core has 2 disks: `flarum-assets` and `flarum-avatars`. + +### Using existing disks + +To access a disk, you'll need to retrieve it from the [Filesystem Factory](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Factory.html). To do so, you should inject the factory contract in your class, and access the disks you need. + +Let's take a look at core's [`DeleteLogoController`](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Controller/DeleteLogoController.php#L19-L58) for an example: + +```php +settings = $settings; + $this->uploadDir = $filesystemFactory->disk('flarum-assets'); + } + + /** + * {@inheritdoc} + */ + protected function delete(ServerRequestInterface $request) + { + RequestUtil::getActor($request)->assertAdmin(); + + $path = $this->settings->get('logo_path'); + + $this->settings->set('logo_path', null); + + if ($this->uploadDir->exists($path)) { + $this->uploadDir->delete($path); + } + + return new EmptyResponse(204); + } +} +``` + +The object returned by `$filesystemFactory->disk(DISK_NAME)` implements the [Illuminate\Contracts\Filesystem\Cloud](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Cloud.html) interface, and can be used to create/get/move/delete files, and to get the URL to a resource. + +### Declaring new disks + +Some extensions will want to group their resources / uploads onto a custom disk as opposed to using `flarum-assets` or `flarum-avatars`. + +This can be done via the `Filesystem` extender: + +```php +use Flarum\Extend; + +return [ + (new Extend\Filesystem) + ->disk('flarum-uploads', function (Paths $paths, UrlGenerator $url) { + return [ + 'root' => "$paths->public/assets/uploads", + 'url' => $url->to('forum')->path('assets/uploads') + ]; + }); +``` + +Since all disks use the local filesystem by default, you'll need to provide a base path and base URL for the local filesystem. + +The config array can contain other entries supported by [Laravel disk config arrays](https://laravel.com/docs/8.x/filesystem#configuration). The `driver` key should not be provided, and will be ignored. + +## Storage drivers + +Flarum selects the active driver for each disk by checking the `disk_driver.DISK_NAME` key in the [settings repository](settings.md) and [config.php file](../config.md). If no driver is configured, or the configured driver is unavailable, Flarum will default to the `local` driver. + +You can define new storage drivers by implementing the [`Flarum\Filesystem\DriverInterface` interface](https://github.com/flarum/framework/blob/main/framework/core/src/Filesystem/DriverInterface.php#L16), and registering it via the `Filesystem` extender: + +```php +use Flarum\Extend; + +return [ + (new Extend\Filesystem) + ->driver('aws-with-cdn', AwsWithCdnDriver::class); +``` + +Filesystem storage drivers are a very powerful tool that allows you to completely customize file storage locations, attach arbitrary CDNs, and otherwise extend the filesystem / cloud storage integration layer. + +:::danger + +Some drivers might try to index their filesystem every time the driver is instantiated, even if only the `url` method is needed. This can have serious performance implications. In most cases, you'll want to ensure that your driver's `url` method does not ping the remote filesystem. Similarly, the remote filesystem should usually not be accessed until operations are actually executed. + +::: + +## GUI and Admin Configuration + +Flarum does not currently provide a GUI for selecting drivers for disks, or for entering settings for drivers. This might be added in the future. For now, extensions are responsible for providing a GUI for their disks and drivers. + +As noted [above](#storage-drivers), if your extension provides a GUI for selecting drivers for a disk, it should modify the `disk_driver.DISK_NAME` key in settings. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md new file mode 100644 index 000000000..95ccd4d71 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md @@ -0,0 +1,42 @@ +# Biçimlendirme + +Flarum uses the powerful [s9e TextFormatter](https://github.com/s9e/TextFormatter) library to format posts from plain markup into HTML. You should become familiar with [how TextFormatter works](https://s9etextformatter.readthedocs.io/Getting_started/How_it_works/) before you attempt to extend it. + +In Flarum, post content is formatted with a minimal TextFormatter configuration by default. The bundled **Markdown** and **BBCode** extensions simply enable the respective plugins on this TextFormatter configuration. + +## Configuration + +You can configure the TextFormatter `Configurator` instance, as well as run custom logic during parsing and rendering, using the `Formatter` extender: + +```php +use Flarum\Extend; +use Psr\Http\Message\ServerRequestInterface as Request; +use s9e\TextFormatter\Configurator; +use s9e\TextFormatter\Parser; +use s9e\TextFormatter\Renderer; + +return [ + (new Extend\Formatter) + // Add custom text formatter configuration + ->configure(function (Configurator $config) { + $config->BBCodes->addFromRepository('B'); + }) + // Modify raw text before it is parsed. + // This callback should return the modified text. + ->parse(function (Parser $parser, $context, $text) { + // custom logic here + return $newText; + }) + // Modify the XML to be rendered before rendering. + // This callback should return the new XML. + // For example, in the mentions extension, this is used to + // provide the username and display name of the user being mentioned. + // Make sure that the last $request argument is nullable (or omitted entirely). + ->render(function (Renderer $renderer, $context, $xml, Request $request = null) { + // custom logic here + return $newXml; + }) +]; +``` + +With a good understanding of TextFormatter, this will allow you to achieve anything from simple BBCode tag additions to more complex formatting tasks like Flarum's **Mentions** extension. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/forms.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/forms.md new file mode 100644 index 000000000..682243c95 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/forms.md @@ -0,0 +1,108 @@ +# Formlar ve İstekler + +In this article, we'll go over some frontend tools that are available to us for building and managing forms, as well how to send HTTP requests via Flarum. + +## Form Components + +As with any interactive site, you will likely want to include forms in some pages and modals. Flarum provides some components to make building (and styling!) these forms easier. Please see the linked API documentation for each of these to learn more about its accepted attrs. + +- The [`flarum/common/components/FieldSet` component](https://api.docs.flarum.org/js/master/class/src/common/components/fieldset.js~fieldset) wraps its children in a HTML fieldset tag, with a legend. +- The [`flarum/common/components/Select` component](https://api.docs.flarum.org/js/master/class/src/common/components/select.js~select) is a stylized select input. +- The [`flarum/common/components/Switch`](https://api.docs.flarum.org/js/master/class/src/common/components/switch.js~switch) and [`flarum/common/components/Checkbox` components](https://api.docs.flarum.org/js/master/class/src/common/components/checkbox.js~checkbox) are stylized checkbox input components. Their `loading` attr can be set to `true` to show a loading indicator. +- The [`flarum/common/components/Button` component](https://api.docs.flarum.org/js/master/class/src/common/components/button.js~button) is a stylized button, and is used frequently throughout Flarum. + +You'll typically want to assign logic for reacting to input changes via Mithril's `on*` attrs, not external listeners (as is common with jQuery or plain JS). For example: + +```jsx +import Component from 'flarum/common/Component'; +import FieldSet from 'flarum/common/components/FieldSet'; +import Button from 'flarum/common/components/Button'; +import Switch from 'flarum/common/components/Switch'; + + +class FormComponent extends Component { + oninit(vnode) { + this.textInput = ""; + this.booleanInput = false; + } + + view() { + return ( +
+
+ this.textInput = e.target.value}> + + this.booleanInput = val}> + +
+ +
+ ) + } + + onsubmit() { + // Some form handling logic here + } +} +``` + +Don't forget to use [translations](i18n.md)! + + +## Streams, bidi, and withAttr + +Flarum provides [Mithril's Stream](https://mithril.js.org/stream.html) as `flarum/common/util/Stream`. This is a very powerful reactive data structure, but is most commonly used in Flarum as a wrapper for form data. Its basic usage is: + +```js +import Stream from 'flarum/common/utils/Stream'; + + +const value = Stream("hello!"); +value() === "hello!"; // true +value("world!"); +value() === "world!"; // true +``` + +In Flarum forms, streams are frequently used together with the bidi attr. Bidi stands for bidirectional binding, and is a common pattern in frontend frameworks. Flarum patches Mithril with the [`m.attrs.bidi` library](https://github.com/tobyzerner/m.attrs. This abstracts away input processing in Mithril. For instance: + +```jsx +import Stream from 'flarum/common/utils/Stream'; + +const value = Stream(); + +// Without bidi + value(e.target.value)}> + +// With bidi + +``` + +You can also use the `flarum/common/utils/withAttr` util for simplified form processing. `withAttr` calls a callable, providing as an argument some attr of the DOM element tied to the component in question: + +```jsx +import Stream from 'flarum/common/utils/Stream'; +import withAttr from 'flarum/common/utils/withAttr'; + +const value = Stream(); + +// With a stream + + +// With any callable + { + // Some custom logic here +})}> +``` + +## Making Requests + +In our [models](models.md) documentation, you learned how to work with models, and save model creation, changes, and deletion to the database via the Store util, which is just a wrapper around Flarum's request system, which itself is just a wrapper around [Mithril's request system](https://mithril.js.org/request.html). + +Flarum's request system is available globally via `app.request(options)`, and has the following differences from Mithril's `m.request(options)`: + +- It will automatically attach `X-CSRF-Token` headers. +- It will convert `PATCH` and `DELETE` requests into `POST` requests, and attach a `X-HTTP-Method-Override` header. +- If the request errors, it will show an alert which, if in debug mode, can be clicked to show a full error modal. +- You can supply a `background: false` option, which will run the request synchronously. However, this should almost never be done. + +Otherwise, the API for using `app.request` is the same as that for `m.request`. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md new file mode 100644 index 000000000..d01da8e41 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md @@ -0,0 +1,218 @@ +# Ön Uç Sayfaları ve Çözücüler + +As explained in the [Routes and Content](routes.md#frontend-routes) documentation, we can use Mithril's routing system to show different [components](frontend.md#components) for different routes. Mithril allows you to use any component you like, even a Modal or Alert, but we recommend sticking to component classes that inherit the `Page` component. + +## The Page Component + +We provide `flarum/common/components/Page` as a base class for pages in both the `admin` and `forum` frontends. It has a few benefits: + +- Automatically updates [`app.current` and `app.previous` PageState](#pagestate) when switching from one route to another. +- Automatically closes the modal and drawer when switching from one route to another. +- Applies `this.bodyClass` (if defined) to the '#app' HTML element when the page renders. +- It's also good for consistency's sake to use a common base class for all pages. +- If the page's `scrollTopOnCreate` attribute is set to `false` in `oninit`, the page won't be scrolled to the top when changed. +- If the page's `useBrowserScrollRestoration` is set to `false` in `oninit`, the browser's automatic scroll restoration won't be used on that page. + +Page components work just like any other inherited component. For a (very simple) example: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + view() { + return

Hello!

+ } +} +``` + +### Setting Page as Homepage + +Flarum uses a setting to determine which page should be the homepage: this gives admins flexibility to customize their communities. To add your custom page to the homepage options in Admin, you'll need to extend the `BasicsPage.homePageItems` method with your page's path. + +An example from the [Tags extension](https://github.com/flarum/tags/blob/master/js/src/admin/addTagsHomePageOption.js): + +```js +import { extend } from 'flarum/common/extend'; +import BasicsPage from 'flarum/common/components/BasicsPage'; + +export default function() { + extend(BasicsPage.prototype, 'homePageItems', items => { + items.add('tags', { + path: '/tags', + label: app.translator.trans('flarum-tags.admin.basics.tags_label') + }); + }); +} +``` + +To learn how to set up a path/route for your custom page, see the [relevant documentation](routes.md). + +### Page Titles + +Often, you'll want some custom text to appear in the browser tab's title for your page. For instance, a tags page might want to show "Tags - FORUM NAME", or a discussion page might want to show the title of the discussion. + +To do this, your page should include calls to `app.setTitle()` and `app.setTitleCount()` in its `oncreate` [lifecycle hook](frontend.md) (or when data is loaded, if it pulls in data from the API). + +For example: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + oncreate(vnode) { + super.oncreate(vnode); + + app.setTitle("Cool Page"); + app.setTitleCount(0); + } + + view() { + // ... + } +} + +export default class CustomPageLoadsData extends Page { + oninit(vnode) { + super.oninit(vnode); + + app.store.find("users", 1).then(user => { + app.setTitle(user.displayName()); + app.setTitleCount(0); + }) + } + + view() { + // ... + } +} +``` + +Please note that if your page is [set as the homepage](#setting-page-as-homepage), `app.setTitle()` will clear the title for simplicity. It should still be called though, to prevent titles from previous pages from carrying over. + +## PageState + +Sometimes, we want to get information about the page we're currently on, or the page we've just come from. To allow this, Flarum creates (and stores) instances of [`PageState`](https://api.docs.flarum.org/js/master/class/src/common/states/pagestate.js~pagestate) as `app.current` and `app.previous`. These store: + +- The component class being used for the page +- A collection of data that each page sets about itself. The current route name is always included. + +Data can be set to, and retrieved from, Page State using: + +```js +app.current.set(KEY, DATA); +app.current.get(KEY); +``` + +For example, this is how the Discussion Page makes its [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) instance globally available. + +You can also check the type and data of a page using `PostStreamState`'s `matches` method. For instance, if we want to know if we are currently on a discussion page: + +```jsx +import IndexPage from 'flarum/forum/components/DiscussionPage'; +import DiscussionPage from 'flarum/forum/components/DiscussionPage'; + +// To just check page type +app.current.matches(DiscussionPage); + +// To check page type and some data +app.current.matches(IndexPage, {routeName: 'following'}); +``` + +## Admin Pages + +See the [Admin Dashboard documentation](admin.md) for more information on tools specifically available to admin pages (and how to override the admin page for your extension). + +## Route Resolvers (Advanced) + +[Advanced use cases](https://mithril.js.org/route.html#advanced-component-resolution) can take advantage of Mithril's [route resolver system](https://mithril.js.org/route.html#routeresolver). Flarum actually already wraps all its components in the `flarum/common/resolvers/DefaultResolver` resolver. This has the following benefits: + +- It passes a `routeName` attr to the current page, which then provides it to `PageState` +- It assigns a [key](https://mithril.js.org/keys.html#single-child-keyed-fragments) to the top level page component. When the route changes, if the top level component's key has changed, it will be completely rerendered (by default, Mithril does not rerender components when switching from one page to another if both are handled by the same component). + +### Using Route Resolvers + +There are actually 3 ways to set the component / route resolver when registering a route: + +- the `resolver` key can be used to provide an **instance** of a route resolver. This instance should define which component should be used, and hardcode the route name to be passed into it. This instance will be used without any modifications by Flarum. +- The `resolverClass` key AND `component` key can be used to provide a **class** that will be used to instantiate a route resolver, to be used instead of Flarum's default one, as well as the component to use. Its constructor should take 2 arguments: `(component, routeName)`. +- The `component` key can be used alone to provide a component. This will result in the default behavior. + +For example: + +```js +// See above for a custom page example +import CustomPage from './components/CustomPage'; +// See below for a custom resolver example +import CustomPageResolver from './resolvers/CustomPageResolver'; + +// Use a route resolver instance +app.routes['resolverInstance'] = {path: '/custom/path/1', resolver: { + onmatch: function(args) { + if (!app.session.user) return m.route.SKIP; + + return CustomPage; + } +}}; + +// Use a custom route resolver class +app.routes['resolverClass'] = {path: '/custom/path/2', resolverClass: CustomPageResolver, component: CustomPage}; + +// Use the default resolver class (`flarum/common/resolvers/DefaultResolver`) +app.routes['resolverClass'] = {path: '/custom/path/2', component: CustomPage}; +``` + +### Custom Resolvers + +We strongly encourage custom route resolvers to extend `flarum/common/resolvers/DefaultResolver`. For example, Flarum's `flarum/forum/resolvers/DiscussionPageResolver` assigns the same key to all links to the same discussion (regardless of the current post), and triggers scrolling when using `m.route.set` to go from one post to another on the same discussion page: + +```js +import DefaultResolver from '../../common/resolvers/DefaultResolver'; + +/** + * This isn't exported as it is a temporary measure. + * A more robust system will be implemented alongside UTF-8 support in beta 15. + */ +function getDiscussionIdFromSlug(slug: string | undefined) { + if (!slug) return; + return slug.split('-')[0]; +} + +/** + * A custom route resolver for DiscussionPage that generates the same key to all posts + * on the same discussion. It triggers a scroll when going from one post to another + * in the same discussion. + */ +export default class DiscussionPageResolver extends DefaultResolver { + static scrollToPostNumber: number | null = null; + + makeKey() { + const params = { ...m.route.param() }; + if ('near' in params) { + delete params.near; + } + params.id = getDiscussionIdFromSlug(params.id); + return this.routeName.replace('.near', '') + JSON.stringify(params); + } + + onmatch(args, requestedPath, route) { + if (route.includes('/d/:id') && getDiscussionIdFromSlug(args.id) === getDiscussionIdFromSlug(m.route.param('id'))) { + DiscussionPageResolver.scrollToPostNumber = parseInt(args.near); + } + + return super.onmatch(args, requestedPath, route); + } + + render(vnode) { + if (DiscussionPageResolver.scrollToPostNumber !== null) { + const number = DiscussionPageResolver.scrollToPostNumber; + // Scroll after a timeout to avoid clashes with the render. + setTimeout(() => app.current.get('stream').goToNumber(number)); + DiscussionPageResolver.scrollToPostNumber = null; + } + + return super.render(vnode); + } +} +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md new file mode 100644 index 000000000..b8af97c41 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md @@ -0,0 +1,422 @@ +# Ön Uç Geliştirme + +This page describes how to make changes to Flarum's user interface. How to add buttons, marquees, and blinking text. 🤩 + +[Remember](/extend/start.md#architecture), Flarum's frontend is a **single-page JavaScript application**. There's no Twig, Blade, or any other kind of PHP template to speak of. The few templates that are present in the backend are only used to render search-engine-optimized content. All changes to the UI need to be made via JavaScript. + +Flarum has two separate frontend applications: + +* `forum`, the public side of your forum where users create discussions and posts. +* `admin`, the private side of your forum where, as an administrator of your forum, you configure your Flarum installation. + +They share the same foundational code, so once you know how to extend one, you know how to extend both. + +:::tip Typings! + +Along with new TypeScript support, we have a [`tsconfig` package](https://www.npmjs.com/package/flarum-tsconfig) available, which you should install as a dev dependency to gain access to our typings. Make sure you follow the instructions in the [package's README](https://github.com/flarum/flarum-tsconfig#readme) to configure typings support. + +::: + +## Transpilation and File Structure + +This portion of the guide will explain the necessary file setup for extensions. Once again, we highly recommend using the [Flarum CLI](https://github.com/flarum/cli) to set up the file structure for you. That being said, you should still read this to understand what's going on beneath the surface. + +Before we can write any JavaScript, we need to set up a **transpiler**. This allows us to use [TypeScript](https://www.typescriptlang.org/) and its magic in Flarum core and extensions. + +In order to do this transpilation, you need to be working in a capable environment. No, not the home/office kind of environment – you can work in the bathroom for all I care! I'm talking about the tools that are installed on your system. You'll need: + +* Node.js and npm ([Download](https://nodejs.org/en/download/)) +* Webpack (`npm install -g webpack`) + +This can be tricky because everyone's system is different. From the OS you're using, to the program versions you have installed, to the user access permissions – I get chills just thinking about it! If you run into trouble, ~~tell him I said hi~~ use [Google](https://google.com) to see if someone has encountered the same error as you and found a solution. If not, ask for help from the [Flarum Community](https://discuss.flarum.org) or on the [Discord chat](https://flarum.org/discord/). + +It's time to set up our little JavaScript transpilation project. Create a new folder in your extension called `js`, then pop in a couple of new files. A typical extension will have the following frontend structure: + +``` +js +├── dist (compiled js is placed here) +├── src +│ ├── admin +│ └── forum +├── admin.js +├── forum.js +├── package.json +├── tsconfig.json +└── webpack.config.js +``` + +### package.json + +```json +{ + "private": true, + "name": "@acme/flarum-hello-world", + "dependencies": { + "flarum-webpack-config": "^1.0.0", + "webpack": "^4.0.0", + "webpack-cli": "^4.0.0" + }, + "devDependencies": { + "flarum-tsconfig": "^1.0.0" + }, + "scripts": { + "dev": "webpack --mode development --watch", + "build": "webpack --mode production" + } +} +``` + +This is a standard JS [package-description file](https://docs.npmjs.com/files/package.json), used by npm and Yarn (Javascript package managers). You can use it to add commands, js dependencies, and package metadata. We're not actually publishing a npm package: this is simply used to collect dependencies. + +Please note that we do not need to include `flarum/core` or any flarum extensions as dependencies: they will be automatically packaged when Flarum compiles the frontends for all extensions. + +### webpack.config.js + +```js +const config = require('flarum-webpack-config'); + +module.exports = config(); +``` + +[Webpack](https://webpack.js.org/concepts/) is the system that actually compiles and bundles all the javascript (and its dependencies) for our extension. To work properly, our extensions should use the [official flarum webpack config](https://github.com/flarum/flarum-webpack-config) (shown in the above example). + +### tsconfig.json + +```json +{ + // Use Flarum's tsconfig as a starting point + "extends": "flarum-tsconfig", + // This will match all .ts, .tsx, .d.ts, .js, .jsx files in your `src` folder + // and also tells your Typescript server to read core's global typings for + // access to `dayjs` and `$` in the global namespace. + "include": ["src/**/*", "../vendor/flarum/core/js/dist-typings/@types/**/*"], + "compilerOptions": { + // This will output typings to `dist-typings` + "declarationDir": "./dist-typings", + "baseUrl": ".", + "paths": { + "flarum/*": ["../vendor/flarum/core/js/dist-typings/*"] + } + } +} +``` + +This is a standard configuration file to enable support for Typescript with the options that Flarum needs. + +Always ensure you're using the latest version of this file: https://github.com/flarum/flarum-tsconfig#readme. + +Even if you choose not to use TypeScript in your extension, which is supported natively by our Webpack config, it's still recommended to install the `flarum-tsconfig` package and to include this configuration file so that your IDE can infer types for our core JS. + +To get the typings working, you'll need to run `composer update` in your extension's folder to download the latest copy of Flarum's core into a new `vendor` folder. Remember not to commit this folder if you're using a version control system such as Git. + +You may also need to restart your IDE's TypeScript server. In Visual Studio Code, you can press F1, then type "Restart TypeScript Server" and hit ENTER. This might take a minute to complete. + +### admin.js and forum.js + +These files contain the root of our actual frontend JS. You could put your entire extension here, but that would not be well organized. For this reason, we recommend putting the actual source code in `src`, and having these files just export the contents of `src`. For instance: + +```js +// admin.js +export * from './src/admin'; + +// forum.js +export * from './src/forum'; +``` + +### src + +If following the recommendations for `admin.js` and `forum.js`, we'll want to have 2 subfolders here: one for `admin` frontend code, and one for `forum` frontend code. If you have components, models, utils, or other code that is shared across both frontends, you may want to create a `common` subfolder and place it there. + +Structure for `admin` and `forum` is identical, so we'll just show it for `forum` here: + +``` +src/forum/ +├── components/ +|-- models/ +├── utils/ +└── index.js +``` + +`components`, `models`, and `utils` are directories that contain files where you can define custom [components](#components), [models](models.md#frontend-models), and reusable util helper functions. Please note that this is all simply a recommendation: there's nothing forcing you to use this particular file structure (or any other file structure). + +The most important file here is `index.js`: everything else is just extracting classes and functions into their own files. Let's go over a typical `index.js` file structure: + +```js +import { extend, override } from 'flarum/common/extend'; + +// We provide our extension code in the form of an "initializer". +// This is a callback that will run after the core has booted. +app.initializers.add('acme-flarum-hello-world', function(app) { + // Your Extension Code Here + console.log("EXTENSION NAME is working!"); +}); +``` + +We'll go over tools available for extensions below. + +### Importing + +You should familiarize yourself with proper syntax for [importing js modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import), as most extensions larger than a few lines will split their js into multiple files. + +Pretty much every Flarum extension will need to import *something* from Flarum Core. Like most extensions, core's JS source code is split up into `admin`, `common`, and `forum` folders. You can import the file by prefixing its path in the Flarum core source code with `flarum`. So `admin/components/AdminLinkButton` is available as `flarum/admin/components/AdminLinkButton`, `common/Component` is available as `flarum/common/Component`, and `forum/states/PostStreamState` is available as `flarum/forum/states/PostStreamState`. + +In some cases, an extension may want to extend code from another flarum extension. This is only possible for extensions which explicitly export their contents. + +* `flarum/tags` and `flarum/flags` are currently the only bundled extensions that allow extending their JS. You can import their contents from `flarum/{EXT_NAME}/PATH` (e.g. `flarum/tags/components/TagHero`). +* The process for extending each community extension is different; you should consult documentation for each individual extension. + +### Transpilation + +OK, time to fire up the transpiler. Run the following commands in the `js` directory: + +```bash +npm install +npm run dev +``` + +This will compile your browser-ready JavaScript code into the `js/dist/forum.js` file, and keep watching for changes to the source files. Nifty! + +When you've finished developing your extension (or before a new release), you'll want to run `npm run build` instead of `npm run dev`: this builds the extension in production mode, which makes the source code smaller and faster. + +## Asset Registration + +### JavaScript + +In order for your extension's JavaScript to be loaded into the frontend, we need to tell Flarum where to find it. We can do this using the `Frontend` extender's `js` method. Add it to your extension's `extend.php` file: + +```php +js(__DIR__.'/js/dist/forum.js') +]; +``` + +Flarum will make anything you `export` from `forum.js` available in the global `flarum.extensions['acme-hello-world']` object. Thus, you may choose to expose your own public API for other extensions to interact with. + +:::tip External Libraries + +Only one main JavaScript file per extension is permitted. If you need to include any external JavaScript libraries, either install them with NPM and `import` them so they are compiled into your JavaScript file, or see [Routes and Content](/extend/routes.md) to learn how to add extra `'; + }) +]; +``` + +You can also add content onto your frontend route registrations: + +```php +return [ + (new Extend\Frontend('forum')) + ->route('/users', 'acme.users', function (Document $document, Request $request) { + $document->title = 'Users'; + }) +]; +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/search.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/search.md new file mode 100644 index 000000000..19486a0fd --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/search.md @@ -0,0 +1,202 @@ +# Arama + +Flarum treats searching and filtering as parallel but distinct processes. Which process is used to handle a request to a [`List` API endpoint](/extend/api.md#api-endpoints) depends on the query parameters: + +- Filtering is applied when the `filter[q]` query param is omitted. Filters represent **structured** queries: for instance, you might want to only retrieve discussions in a certain category, or users who registered before a certain date. Filtering computes results based entirely on `filter[KEY] = VALUE` query parameters. +- Searching is applied when the `filter[q]` query param is included. Searches represent **unstructured** queries: the user submits an arbitrary string, and data records that "match" it are returned. For instance, you might want to search discussions based on the content of their posts, or users based on their username. Searching computes results based solely on parsing the `filter[q]` query param: all other `filter[KEY] = VALUE` params are ignored when searching. It's important to note that searches aren't entirely unstructured: the dataset being searched can be constrained by gambits (which are very similar to filters, and will be explained later). + +This distinction is important because searches and filters have very different use cases: filters represent *browsing*: that is, the user is passively looking through some category of content. In contrast, searches represent, well, *searching*: the user is actively looking for content based on some criteria. + +Flarum implements searching and filtering via per-model `Searcher` and `Filterer` classes (discussed in more detail below). Both classes accept a [`Flarum\Query\QueryCriteria`](https://api.docs.flarum.org/php/master/flarum/query/querycriteria) instance (a wrapper around the user and query params), and return a [`Flarum\Query\QueryResults`](https://api.docs.flarum.org/php/master/flarum/query/queryresults) instance (a wrapper around an Eloquent model collection). This common interface means that adding search/filter support to models is quite easy. + +One key advantage of this split is that it allows searching to be implemented via an external service, such as ElasticSearch. For larger communities, this can be significantly more performant and accurate. There isn't a dedicated extender for this yet, so for now, replacing the default Flarum search driver requires overriding the container bindings of `Searcher` classes. This is a highly advanced use case; if you're interested in doing this, please reach out on our [community forums](https://discuss.flarum.org/). + +Remember that the [JSON:API schema](https://jsonapi.org/format) is used for all API requests. + +:::tip Reuse Code + +Often, you might want to use the same class as both a `Filter` and a `Gambit` (both explained below). Your classes can implement both interface; see Flarum core's [`UnreadFilterGambit`](https://github.com/flarum/framework/blob/main/framework/core/src/Discussion/Query/UnreadFilterGambit.php) for an example. + +::: + +:::tip Query Builder vs Eloquent Builder + +`Filter`s, `Gambit`s, filter mutators, and gambit mutators (all explained below) receive a "state" parameter, which wraps + +::: + +## Filtering + +Filtering constrains queries based on `Filters` (highlighted in code to avoid confusion with the process of filtering), which are classes that implement `Flarum\Filter\FilterInterface` and run depending on query parameters. After filtering is complete, a set of callbacks called "filter mutators" run for every filter request. + +When the `filter` method on a `Filterer` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Filter/AbstractFilterer.php#L50-L93)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Filterer` class's `getQuery()` method. +2. We loop through all `filter[KEY] = VALUE` query params. For each of these, any `Filter`s registered to the model whose `getFilterKey()` method matches the query param `KEY` is applied. `Filter`s can be negated by providing the query param as `filter[-KEY] = VALUE`. Whether or not a `Filter` is negated is passed to it as an argument: implementing negation is up to the `Filter`s. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "filter mutators" are applied. These are callbacks that receive the filter state (a wrapper around the query builder and current user) and filter criteria, and perform some arbitrary changes. All "filter mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Filtering for an Existing Model + +Let's say you've added a `country` column to the User model, and would like to filter users by country. We'll need to define a custom `Filter`: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +Note that `FilterState` is a wrapper around the Eloquent builder's underlying Query builder and the current user. + +Also, let's pretend that for some reason, we want to omit any users that have a different country from the current user on ANY filter. We can use a "filter mutator" for this: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +Now, all we need to do is register these via the Filter extender: + +```php + // Other extenders + (new Extend\Filter(UserFilterer::class)) + ->addFilter(CountryFilter::class) + ->addFilterMutator(OnlySameCountryFilterMutator::class), + // Other extenders +``` + +### Add Filtering to a New Model + +To filter a model that doesn't support filtering, you'll need to create a subclass of `Flarum/Filter/AbstractFilterer` for that model. For an example, see core's [UserFilterer](https://github.com/flarum/framework/blob/main/framework/core/src/User/Filter/UserFilterer.php). + +Then, you'll need to use that filterer in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +## Searching + +Searching constrains queries by applying `Gambit`s, which are classes that implement `Flarum\Search\GambitInterface`, based on the `filter[q]` query param. After searching is complete, a set of callbacks called "search mutators" run for every search request. + +When the `search` method on a `Searcher` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Search/AbstractSearcher.php#L55-L79)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Searcher` class's `getQuery()` method. +2. The `filter[q]` param is split by spaces into "tokens". Each token is matched against the model's registered `Gambit`s (each gambit has a `match` method). For any tokens that match a gambit, that gambit is applied, and the token is removed from the query string. Once all regular `Gambit`s have ran, all remaining unmatched tokens are passed to the model's `FullTextGambit`, which implements the actual searching logic. For example if searching discussions, in the `filter[q]` string `'author:1 hello is:hidden' world`, `author:1` and `is:hidden` would get matched by core's Author and Hidden gambits, and `'hello world'` (the remaining tokens) would be passed to the `DiscussionFulltextGambit`. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "search mutators" are applied. These are callbacks that receive the search state (a wrapper around the query builder and current user) and criteria, and perform some arbitrary changes. All "search mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Searching for an Existing Model + +Let's reuse the "country" examples we used above, and see how we'd implement the same things for searching: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +:::warning No Spaces in Gambit Patterns! + +Flarum splits the `filter[q]` string into tokens by splitting it at spaces. This means that your custom gambits can NOT use spaces as part of their pattern. + +::: + +:::tip AbstractRegexGambit + +All a gambit needs to do is implement `Flarum\Search\GambitInterface`, which receives the search state and a token. It should return if this gambit applies for the given token, and if so, make whatever mutations are necessary to the query builder accessible as `$searchState->getQuery()`. + +However, for most gambits, the `AbstractRegexGambit` abstract class (used above) should be used as a base class. This makes it a lot simpler to match and apply gambits. + +::: + +Similarly, the search mutator we need is almost identical to the filter mutator from before: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +We can register these via the `SimpleFlarumSearch` extender (in the future, the `Search` extender will be used for registering custom search drivers): + +```php + // Other extenders + (new Extend\SimpleFlarumSearch(UserSearcher::class)) + ->addGambit(CountryGambit::class) + ->addSearchMutator(OnlySameCountrySearchMutator::class), + // Other extenders +``` + +### Add Searching to a New Model + +To support searching for a model, you'll need to create a subclass of `Flarum/Search/AbstractSearcher` for that model. For an example, see core's [UserSearcher](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/UserSearcher.php). + +Then, you'll need to use that searcher in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +Every searcher **must** have a fulltext gambit (the logic that actually does the searching). Otherwise, it won't be booted by Flarum, and you'll get an error. See core's [FulltextGambit for users](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/Gambit/FulltextGambit.php) for an example. You can set (or override) the full text gambit for a searcher via the `SimpleFlarumSearch` extender's `setFullTextGambit()` method. + +### Search Drivers + +Coming soon! + +## Frontend Tools + +Coming soon! diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md new file mode 100644 index 000000000..30fef15df --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md @@ -0,0 +1,65 @@ +# Servis Sağlayıcı + +As noted throughout this documentation, Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection. [Service Providers](https://laravel.com/docs/8.x/providers) allow low-level configuration and modification of the Flarum backend. The most common use case for service providers is to create, modify, or replace container bindings. That being said, service providers allow you full access to run whatever logic you need during application boot with access to the container. + +:::caution Advanced Use Only!!! + +Unlike with other extenders, the Service Provider layer is NOT use-case driven, and is NOT considered public API. It is subject to change at any time, without notice or deprecation. This should only be used if you know what you're doing, and the other extenders don't satisfy your use case. + +::: + +## Flarum Boot Process + +To understand service providers, you must first understand the order in which Flarum boots. Most of this happens in [Flarum\Foundation\InstalledSite](https://github.com/flarum/framework/blob/main/framework/core/src/Foundation/InstalledSite.php) + +1. The container and application are initialized, and essential bindings (config, environment, logger) are registered +2. The `register` methods of all core service providers are run. +3. The `extend` methods of all extenders used by all enabled extensions are run. +4. The `extend` methods of all extenders used in the Flarum site's local `extend.php` are run. +5. The `boot` methods of all core service providers are run. + +## Custom Service Providers + +A custom service provider should extend `Flarum\Foundation\AbstractServiceProvider`, and can have a `boot` and a `register` method. For example: + +```php +container->resolving(SomeClass::class, function ($container) { + return new SomeClass($container->make('some.binding')); + }); + } + + public function boot(Container $container) + { + // custom logic here + } +} +``` + +The `register` method will run during step (3) above, and the `boot` method will run during step (5) above. In the `register` method, the container is available via `$this->container`. In the `boot` method, the container (or any other arguments), should be injected via typehinted method arguments. + +Flarum does not currently support Laravel Octane, but some [best practices](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane), like using the `$container` argument inside `bind`, `singleton`, and `resolving` callbacks instead of `$this->container` should be used. See the [Octane documentation](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane) for more information. + +To actually register your custom service provider, you can use the `ServiceProvider` extender in `extend.php`: + +```php +register(CustomServiceProvider::class), + // Other extenders +]; +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/settings.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/settings.md new file mode 100644 index 000000000..4fe60d6aa --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/settings.md @@ -0,0 +1,90 @@ +# Ayarlar + +At some point while making an extension, you might want to read some of the forum's settings or store certain settings specific to your extension. Thankfully, Flarum makes this very easy. + +## The Settings Repository + +Reading or changing settings can be done using an implementation of the `SettingsRepositoryInterface`. Because Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection, you don't need to worry about where to obtain such a repository, or how to instantiate one. Instead, you can rely on the container to instantiate your class and inject the correct dependencies. + +```php +settings = $settings; + } +} +``` + +Great! Now the `SettingsRepositoryInterface` is available through `$this->settings` to our class. + +### Reading Settings + +To read settings, all we have to do is use the repository's `get()` function: + +`$this->settings->get('forum_title')` + +The `get()` function accepts two arguments: + +1. The name of the setting you are trying to read. +2. (Optional) A default value if no value has been stored for such a setting. By default, this will be `null`. + +### Storing Settings + +Storing settings ist just as easy, use the `set()` function: + +`$this->settings->set('forum_title', 'Super Awesome Forum')` + +The `set` function also accepts two arguments: + +1. The name of the setting you are trying to change. +2. The value you want to store for this setting. + +### Other Functions + +The `all()` function returns an array of all known settings. + +The `delete($name)` function lets you remove a named setting. + +## Settings in the Frontend + +### Editing Settings + +To learn more about adding settings through the admin dashboard, see the [relevant documentation](admin.md). +### Accessing Settings + +All settings are available in the `admin` frontend via the `app.data.settings` global. However, this is not done in the `forum` frontend, as anyone can access it, and you wouldn't want to leak all your settings! (Seriously, that could be a very problematic data breach). + +Instead, if we want to use settings in the `forum` frontend, we'll need to serialize them and send them alongside the initial forum data payload. + +This can be done via the `Settings` extender. For example: + +**extend.php** + +```php +use Flarum\Extend; + +return [ + (new Extend\Settings) + ->serializeToForum('myCoolSetting', 'my.cool.setting.key') + ->serializeToForum('myCoolSettingModified', 'my.cool.setting.key', function ($retrievedValue) { + // This third argument is optional, and allows us to pass the retrieved setting through some custom logic. + // In this example, we'll append a string to it. + + return "My Cool Setting: $retrievedValue"; + }, "default value!"), +] +``` + +Now, the `my.cool.setting.key` setting will be accessible in the frontend as `app.forum.attribute("myCoolSetting")`, and our modified value will be accessible via `app.forum.attribute("myCoolSettingModified")`. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md new file mode 100644 index 000000000..5eb3657ad --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md @@ -0,0 +1 @@ +# Model Yavaşlatma diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/start.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/start.md new file mode 100644 index 000000000..418dee766 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/start.md @@ -0,0 +1,153 @@ +# Başlangıç + +Flarum eklentisi mi yazmak istiyorsunuz? Doğru yere geldiniz! Bu dökümantasyon sizi bazı temel kavramlara götürecek ve ardından ilk Flarum uzantınızı sıfırdan oluşturacaksınız. + +## Architecture + +Flarum'un nasıl büyüteceğimizi anlamak için, önce Flarum'un nasıl inşa edildiğini biraz anlamamız gerekiyor. + +Flarum'un _ modern _ programlama dillerini ve araçlarını kullandığını bilin. Daha önce sadece WordPress eklentileri oluşturduysanız, kendinizi biraz yetersiz hissedebilirsiniz! Sorun Değil - yeni şeyler öğrenmek ve becerilerinizi geliştirmek için harika bir zaman. However, we would advise that you become somewhat familiar with the technologies described below before proceeding. + +Flarum is made up of three layers: + +* First, there is the **backend**. This is written in [object-oriented PHP](https://laracasts.com/series/object-oriented-bootcamp-in-php), and makes use of a wide array of [Laravel](https://laravel.com/) components and other packages via [Composer](https://getcomposer.org/). You'll also want to familiarize yourself with the concept of [Dependency Injection](https://laravel.com/docs/8.x/container), which is used throughout our backend. + +* Second, the backend exposes a **public API** which allows frontend clients to interface with your forum's data. This is built according to the [JSON:API specification](https://jsonapi.org/). + +* Finally, there is the default web interface which we call the **frontend**. This is a [single-page application](https://en.wikipedia.org/wiki/Single-page_application) which consumes the API. It's built with a simple React-like framework called [Mithril.js](https://mithril.js.org). + +Extensions will often need to interact with all three of these layers to make things happen. For example, if you wanted to build an extension that adds custom fields to user profiles, you would need to add the appropriate database structures in the **backend**, expose that data in the **public API**, and then display it and allow users to edit it on the **frontend**. + +So... how do we extend these layers? + +## Extenders + +In order to extend Flarum, we will be using a concept called **extenders**. Extenders are *declarative* objects that describe in plain terms the goals you are trying to achieve (such as adding a new route to your forum, or executing some code when a new discussion was created). + +Every extender is different. However, they will always look somewhat similar to this: + +```php +// Register a JavaScript and a CSS file to be delivered with the forum frontend +(new Extend\Frontend('forum')) + ->js(__DIR__.'/forum-scripts.js') + ->css(__DIR__.'/forum-styles.css') +``` + +You first create an instance of the extender, and then call methods on it for further configuration. All of these methods return the extender itself, so that you can achieve your entire configuration just by chaining method calls. + +To keep things consistent, we use this concept of extenders in both the backend (in PHP land) and the frontend (in JavaScript land). _Everything_ you do in your extension should be done via extenders, because they are a **guarantee** we are giving to you that a future minor release of Flarum won't break your extension. + +All of the extenders currently available to you from Flarum's core can be found in the [`Extend` namespace](https://github.com/flarum/framework/blob/main/framework/core/src/Extend) [(PHP API documentation)](https://api.docs.flarum.org/php/master/flarum/extend) Extensions may also offer their [own extenders](extensibility.md#custom-extenders). + +## Hello World + +Want to see an extender in action? The `extend.php` file in the root of your Flarum installation is the easiest way to register extenders just for your site. It should return an array of extender objects. Pop it open and add the following: + +```php +content(function (Document $document) { + $document->head[] = ''; + }) +]; +``` + +Now pay your forum a visit for a pleasant (albeit extremely obtrusive) greeting. 👋 + +For simple site-specific customizations – like adding a bit of custom CSS/JavaScript, or integrating with your site's authentication system – the `extend.php` file in your forum's root is great. But at some point, your customization might outgrow it. Or maybe you have wanted to build an extension to share with the community from the get-go. Time to build an extension! + +## Extension Packaging + +[Composer](https://getcomposer.org) is a dependency manager for PHP. It allows applications to easily pull in external code libraries and makes it easy to keep them up-to-date so that security and bug fixes are propagated rapidly. + +As it turns out, every Flarum extension is also a Composer package. That means someone's Flarum installation can "require" a certain extension and Composer will pull it in and keep it up-to-date. Nice! + +During development, you can work on your extensions locally and set up a [Composer path repository](https://getcomposer.org/doc/05-repositories.md#path) to install your local copy. Create a new `packages` folder in the root of your Flarum installation, and then run this command to tell Composer that it can find packages in here: + +```bash +composer config repositories.0 path "packages/*" +``` + +Now let's start building our first extension. Make a new folder inside `packages` for your extension called `hello-world`. We'll put two files in it: `extend.php` and `composer.json`. These files serve as the heart and soul of the extension. + +### extend.php + +The `extend.php` file is just like the one in the root of your site. It will return an array of extender objects that tell Flarum what you want to do. For now, just move over the `Frontend` extender that you had earlier. + +### composer.json + +We need to tell Composer a bit about our package, and we can do this by creating a `composer.json` file: + +```json +{ + "name": "acme/flarum-hello-world", + "description": "Say hello to the world!", + "type": "flarum-extension", + "require": { + "flarum/core": "^1.0.0" + }, + "autoload": { + "psr-4": {"Acme\\HelloWorld\\": "src/"} + }, + "extra": { + "flarum-extension": { + "title": "Hello World", + "icon": { + "name": "fas fa-smile", + "backgroundColor": "#238c59", + "color": "#fff" + } + } + } +} +``` + +* **name** is the name of the Composer package in the format `vendor/package`. + * You should choose a vendor name that’s unique to you — your GitHub username, for example. For the purposes of this tutorial, we’ll assume you’re using `acme` as your vendor name. + * You should prefix the `package` part with `flarum-` to indicate that it’s a package specifically intended for use with Flarum. + +* **description** is a short one-sentence description of what the extension does. + +* **type** MUST be set to `flarum-extension`. This ensures that when someone "requires" your extension, it will be identified as such. + +* **require** contains a list of your extension's own dependencies. + * You'll want to specify the version of Flarum that your extension is compatible with here. + * This is also the place to list other Composer libraries your code needs to work. + +* **autoload** tells Composer where to find your extension's classes. The namespace in here should reflect your extensions' vendor and package name in CamelCase. + +* **extra.flarum-extension** contains some Flarum-specific information, like your extension's display name and how its icon should look. + * **title** is the display name of your extension. + * **icon** is an object which defines your extension's icon. The **name** property is a [Font Awesome icon class name](https://fontawesome.com/icons). All other properties are used as the `style` attribute for your extension's icon. + +See [the composer.json schema](https://getcomposer.org/doc/04-schema.md) documentation for information about other properties you can add to `composer.json`. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +Use the CLI to automatically create your extension's scaffolding: +```bash +$ flarum-cli init +``` + +::: + +### Installing Your Extension + +The final thing we need to do to get up and running is to install your extension. Navigate to the root directory of your Flarum install and run the following command: + +```bash +composer require acme/flarum-hello-world *@dev +``` + +Once that's done, go ahead and fire 'er up on your forum's Administration page, then navigate back to your forum. + +*whizzing, whirring, metal clunking* + +Woop! Hello to you too, extension! + +We're making good progress. We've learned how to set up our extension and use extenders, which opens up a lot of doors. Read on to learn how to extend Flarum's frontend. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md new file mode 100644 index 000000000..28e6c4aa7 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md @@ -0,0 +1,86 @@ +# Static Code Analysis + +Static code analysis is the process of analyzing the source code against a set of rules to find bugs, code smells, and security vulnerabilities. This is a great way to improve the quality of your code and to find potential issues before they are deployed to production. An example is validating the typings of a function to ensure that the function is called with the correct arguments. + +Flarum provides a static code analysis package based on [PHPStan](https://phpstan.org/) that can be added to your extension. In this guide, we will show you how to add the package to your extension and how to run the analysis. + +## Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update the infrastructure for phpstan to your code: + +```bash +$ flarum-cli infra phpstan +``` + +::: + +First you need to require the `flarum/phpstan` package in your extension. You can do this by running the following command in the root of our extension: + +```bash +composer require --dev flarum/phpstan:^1.0 +``` + +Next, you need to create a `phpstan.neon` file in the root of your extension. This file contains [the configuration for PHPStan](https://phpstan.org/config-reference). You can copy the following configuration into the file: + +```neon +includes: + - vendor/flarum/phpstan/extension.neon + +parameters: + # The level will be increased in Flarum 2.0 + level: 5 + paths: + - src + - extend.php + excludePaths: + - *.blade.php + checkMissingIterableValueType: false + databaseMigrationsPath: ['migrations'] +``` + +Finally, you need to add the following script to your `composer.json` file: + +```json +{ + "scripts": { + "analyse:phpstan": "phpstan analyse", + "clear-cache:phpstan": "phpstan clear-result-cache" + }, + "scripts-descriptions": { + "analyse:phpstan": "Run static analysis" + } +} +``` + +## Running the analysis + +To run the analysis, you can run the following command in the root of your extension: + +```bash +composer analyse:phpstan +``` + +If you want to clear the cache before running the analysis, you can run the following command: + +```bash +composer clear-cache:phpstan && composer analyse:phpstan +``` + +## GitHub Actions + +You can also run the analysis using GitHub Actions. Checkout the page on [GitHub Actions](github-actions.md) for more information. + +## Tips + +### Extended model attribute types + +PHPStan needs to be able to determine the type of an attribute added to an existing model. To do this you can use the `Extend\Model(...)->cast(...)` method. + +For example, if your extension were to add a `is_cool` attribute to the `User` model, you can use [attribute casting](https://laravel.com/docs/8.x/eloquent-mutators#attribute-casting) to explicitly define the attribute as boolean. The `flarum/phpstan` package will automatically detect this and communicate it to PHPStan. + +```php +(new Extend\Model(User::class)) + ->cast('is_cool', 'bool'), +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/testing.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/testing.md new file mode 100644 index 000000000..56124ff0e --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/testing.md @@ -0,0 +1,565 @@ +# Deneme + +Automated testing ensures that your extension performs as you expect it to, helps avoid introducing new bugs or regressions, and saves time on manual testing. Flarum currently provides tooling for automated backend unit and integration tests, and we plan to release support for frontend unit testing and E2E testing in the future. + +## Backend Tests + +The `flarum/testing` library is used by core and some bundled extensions for automated unit and integration tests. It is essentially a collection of utils that allow testing Flarum core and extensions with PHPUnit. + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update backend testing infrastructure to your code: + +```bash +$ flarum-cli infra backendTesting +``` + +::: + +```bash +composer require --dev flarum/testing:^1.0 +``` + +Then, you will need to set up a file structure for tests, and add PHPUnit configuration: + +``` +tests +├── fixtures (put any files needed by your tests here (blade templates, images, etc)) +├── integration +│ ├── setup.php (code below) +│ └── PUT INTEGRATION TESTS HERE (organizing into folder is generally a good idea) +├── unit +│ ├── PUT UNIT TESTS HERE +├── phpunit.integration.xml (code below) +└── phpunit.unit.xml (code below) +``` + +#### phpunit.integration.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for integration tests. You can tweak this as needed, but keep `backupGlobals`, `backupStaticAttributes`, and `processIsolation` unchanged. + +```xml + + + + + + + ./integration + + + +``` + +#### phpunit.unit.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for unit tests. You can tweak this as needed. + +```xml + + + + + + + ./unit + + + + + + +``` + +#### setup.php + +This script will be run to set up a testing database / file structure. + +```php +run(); +``` + +#### composer.json Modifications + +We will also want to add scripts to our `composer.json`, so that we can run our test suite via `composer test`. Add some variant of the following to your `composer.json`: + +```json +"scripts": { + "test": [ + "@test:unit", + "@test:integration" + ], + "test:unit": "phpunit -c tests/phpunit.unit.xml", + "test:integration": "phpunit -c tests/phpunit.integration.xml", + "test:setup": "@php tests/integration/setup.php" +}, +"scripts-descriptions": { + "test": "Runs all tests.", + "test:unit": "Runs all unit tests.", + "test:integration": "Runs all integration tests.", + "test:setup": "Sets up a database for use with integration tests. Execute this only once." +} +``` + +#### GitHub Testing Workflow + +To run tests on every commit and pull request, check out the [GitHub Actions](github-actions.md) page. + +--- + +Now that we have everything in place, we need to set up our testing site for integration tests. For this, we will need a MySQL or MariaDb instance, and a place to store testing files. + +Testing database information is configured via the `DB_HOST` (defaults to `localhost`), `DB_PORT` (defaults to `3306`), `DB_DATABASE` (defaults to `flarum_test`), `DB_USERNAME` (defaults to `root`), `DB_PASSWORD` (defaults to `root`), and `DB_PREFIX` (defaults to `''`) environmental variables. The testing tmp directory path is configured via the `FLARUM_TEST_TMP_DIR_LOCAL` or `FLARUM_TEST_TMP_DIR` environmental variables, with the former taking precedence over the latter. If neither are provided, a `tmp` directory will be created in the `vendor` folder of your extension's local install. + +Now that we've provided the needed information, all we need to do is run `composer test:setup` in our extension's root directory, and we have our testing environment ready to go! + +Since [(almost)](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/tests/integration/api/discussions/ListWithFulltextSearchTest.php#L29-L45) all database operations in integration tests are run in transactions, developers working on multiple extensions will generally find it more convenient to use one shared database and tmp directory for testing all their extensions. To do this, set the database config and `FLARUM_TEST_TMP_DIR` environmental variables in your `.bashrc` or `.bash_profile` to the path you want to use, and run the setup script for any one extension (you'll still want to include the setup file in every repo for CI testing via GitHub Actions). You should then be good to go for any Flarum extension (or core). + +### Using Integration Tests + +Flarum's integration test utils are contained in the `Flarum\Testing\integration\TestCase` class. It: + +- Boots (and makes available) an instance of the Flarum application. +- Allows pre-populating the database, enabling extensions, and adding extenders. +- Runs all database changes in transactions, so your test database retains the default post-installation state. +- Allows sending requests through the middleware stack to test HTTP endpoints. + +Your testcase classes should extend this class. + +#### Test Case Setup + +There are several important utilities available for your test cases: + +- The `setting($key, $value)` method allows you to override settings before the app has booted. This is useful if your boot process has logic depending on settings (e.g. which driver to use for some system). +- Similarly, the `config($key, $value)` method allows you to override config.php values before the app has booted. You can use dot-delimited keys to set deep-nested values in the config array. +- The `extension($extensionId)` method will take Flarum IDs of extensions to enable as arguments. Your extension should always call this with your extension's ID at the start of test cases, unless the goal of the test case in question is to confirm some behavior present without your extension, and compare that to behavior when your extension is enabled. If your extension is dependent on other extensions, make sure they are included in the composer.json `require` field (or `require-dev` for [optional dependencies](extending-extensions.md)), and also list their composer package names when calling `extension()`. Note that you must list them in a valid order. +- The `extend($extender)` method takes instances of extenders as arguments, and is useful for testing extenders introduced by your extension for other extensions to use. +- The `prepareDatabase()` method allow you to pre-populate your database. This could include adding users, discussions, posts, configuring permissions, etc. Its argument is an associative array that maps table names to arrays of [record arrays](https://laravel.com/docs/8.x/queries#insert-statements). + +If your test case needs users beyond the default admin user, you can use the `$this->normalUser()` method of the `Flarum\Testing\integration\RetrievesAuthorizedUsers` trait. + +:::warning + +The `TestCase` class will boot a Flarum instance the first time its `app()` method is called. Any uses of `prepareDatabase`, `extend`, or `extension` after this happens will have no effect. Make sure you have done all the setup you need in your test case before calling `app()`, or `database()`, `server()`, or `send()`, which call `app()` implicitly. If you need to make database modifications after the app has booted, you can use the regular Eloquent save method, or the `Illuminate\Database\ConnectionInterface` instance obtained via calling the `database()` method. + +::: + +Of course, since this is all based on PHPUnit, you can use the `setUp()` methods of your test classes for common setup tasks. + +For example: + +```php +setting('my.custom.setting', true); + + // Let's assume our extension depends on tags. + // Note that tags will need to be in your extension's composer.json's `require-dev`. + // Also, make sure you include the ID of the extension currently being tested, unless you're + // testing the baseline without your extension. + $this->extension('flarum-tags', 'my-cool-extension'); + + // Note that this input isn't validated: make sure you're populating with valid, representative data. + $this->prepareDatabase([ + 'users' => [ + $this->normalUser() // Available for convenience. + ], + 'discussions' => [ + ['id' => 1, 'title' => 'some title', 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 1, 'first_post_id' => 1, 'comment_count' => 1] + ], + 'posts' => [ + ['id' => 1, 'number' => 1, 'discussion_id' => 1, 'created_at' => Carbon::now(), 'user_id' => 1, 'type' => 'comment', 'content' => '

something

'] + ] + ]); + + // Most test cases won't need to test extenders, but if you want to, you can. + $this->extend((new CoolExtensionExtender)->doSomething('hello world')); + } + + /** + * @test + */ + public function some_phpunit_test_case() + { + // ... + } + + // ... +} +``` + +#### Sending Requests + +A common application of automated testing is pinging various HTTP endpoints with various data, authenticated as different users. You can use this to ensure that: + +- Users can't access content they're not supported to access. +- Permission-based create/edit/delete operations perform as expected. +- The type and schema of data returned is correct. +- Some desired side effect is applied when pinging an API. +- The basic API operations needed by your extension aren't erroring, and don't break when you make changes. + +`TestCase` provides several utilities: + +- The `request()` method constructs a `Psr\Http\Message\ServerRequestInterface` implementing object from a path, a method, and some options, which can be used for authentication, attaching cookies, or configuring the JSON request body. See the [method docblock](https://github.com/flarum/testing/blob/main/src/integration/TestCase.php) for more information on available options. +- Once you've created a request instance, you can send it (and get a response object back) via the `send()` method. + +For example: + +```php +send( + $this->request('GET', '/api/users', ['authenticatedAs' => 1]) + ->withQueryParams(['filter' => ['q' => 'john group:1'], 'sort' => 'username']) + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + /** + * @test + */ + public function can_create_user() + { + $response = $this->send( + $this->request( + 'POST', + '/api/users', + [ + 'authenticatedAs' => 1, + 'json' => [ + 'data' => [ + 'attributes' => [ + 'username' => 'test', + 'password' => 'too-obscure', + 'email' => 'test@machine.local' + ] + ] + ] + ] + ) + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + // ... +} +``` + +:::caution + +If you want to send query parameters in a GET request, you can't include them in the path; you'll need to add them afterwards with the `withQueryParams` method. + +::: + +:::caution + +This is an extreme edge case, but note that MySQL does not update the fulltext index in transactions, so the standard approach won't work if you're trying to test a modified fulltext query. See [core's approach](https://github.com/flarum/framework/blob/main/framework/core/tests/integration/extenders/SimpleFlarumSearchTest.php) for an example of a workaround. + +::: + +#### Console Tests + +If you want to test custom console commands, you can extend `Flarum\Testing\integration\ConsoleTestCase` (which itself extends the regular `Flarum\Testing\integration\TestCase`). It provides 2 useful methods: + +- `$this->console()` returns an instance of `Symfony\Component\Console\Application` +- `$this->runCommand()` takes an array that will be wrapped in `Symfony\Component\Console\Input\ArrayInput`, and run. See the [Symfony code docblock](https://github.com/symfony/console/blob/5.x/Input/ArrayInput.php#L22) for more information. + +For example: + +```php + 'some:command', // The command name, equivalent of `php flarum some:command` + 'foo' => 'bar', // arguments + '--lorem' => 'ipsum' // options + ]; + + $this->assertEquals('Some Output.', $this->runCommand($input)); + } +} +``` + +### Using Unit Tests + +Unit testing in Flarum uses [PHPUnit](https://phpunit.de/getting-started/phpunit-9.html) and so unit testing in flarum is much like any other PHP application. You can find [general tutorials on testing](https://www.youtube.com/watch?v=9-X_b_fxmRM) if you're also new to php. + +When writing unit tests in Flarum, here are some helpful tips. + +#### Mocking Flarum Services + +Unlike the running app, or even integration tests, there is no app/container/etc to inject service instances into our classes. Now all the useful settings, or helpers your extension use require a _mock_ . We want to limit mocking to just the key services, supporting only the minimum interactions needed to test the contract of our individual functions. + +```php + public function setUp(): void + { + parent::setUp(); + // example - if our setting needs settings, we can mock the settings repository + $settingsRepo = m::mock(SettingsRepositoryInterface::class); + // and then control specific return values for each setting key + $settingsRepo->shouldReceive('get')->with('some-plugin-key')->andReturn('some-value-useful-for-testing'); + // construct your class under test, passing mocked services as needed + $this->serializer = new YourClassUnderTest($settingsRepo); + } +``` + +Some aspects require more mocks. If you're validating authorization interactions for instance you might need to mock your users `User::class` and the request's method that provides them as well! + +``` + $this->actor = m::mock(User::class); + $request = m::mock(Request::class)->makePartial(); + $request->shouldReceive('getAttribute->getActor')->andReturn($this->actor); + $this->actor->shouldReceive('SOME PERMISSION')->andReturn(true/false); +``` + +NOTE: If you find your extension needs _lots and lots_ of mocks, or mocks that feel unrelated, it might be an opportunity to simplify your code, perhaps moving key logic into their own smaller functions (that dont require mocks). + +## Frontend Tests + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update frontend testing infrastructure to your code: + +```bash +$ flarum-cli infra frontendTesting +``` + +::: + +First, you need to install the Jest config dev dependency: + +```bash +$ yarn add --dev @flarum/jest-config +``` + +Then, add the following to your `package.json`: + +```json +{ + "type": "module", + "scripts": { + ..., + "test": "yarn node --experimental-vm-modules $(yarn bin jest)" + } +} +``` + +Rename `webpack.config.js` to `webpack.config.cjs`. This is necessary because Jest doesn't support ESM yet. + +Create a `jest.config.cjs` file in the root of your extension: + +```js +module.exports = require('@flarum/jest-config')(); +``` + +If you are using TypeScript, create tsconfig.test.json with the following content: + +```json +{ + "extends": "./tsconfig.json", + "include": ["tests/**/*"], + "files": ["../../../node_modules/@flarum/jest-config/shims.d.ts"] +} +``` + +Then, you will need to set up a file structure for tests: + +``` +js +├── dist +├── src +├── tests +│ ├── unit +│ │ └── functionTest.test.js +│ ├── integration +│ │ └── componentTest.test.js +├── package.json +├── tsconfig.json +├── tsconfig.test.json +├── jest.config.cjs +└── webpack.config.cjs +``` + +#### GitHub Testing Workflow + +To run tests on every commit and pull request, check out the [GitHub Actions](github-actions.md) page. + +### Using Unit Tests + +Like any other JS project, you can use Jest to write unit tests for your frontend code. Checkout the [Jest docs](https://jestjs.io/docs/using-matchers) for more information on how to write tests. + +Here's a simple example of a unit test fo core's `abbreviateNumber` function: + +```ts +import abbreviateNumber from '../../../../src/common/utils/abbreviateNumber'; + +test('does not change small numbers', () => { + expect(abbreviateNumber(1)).toBe('1'); +}); + +test('abbreviates large numbers', () => { + expect(abbreviateNumber(1000000)).toBe('1M'); + expect(abbreviateNumber(100500)).toBe('100.5K'); +}); + +test('abbreviates large numbers with decimal places', () => { + expect(abbreviateNumber(100500)).toBe('100.5K'); + expect(abbreviateNumber(13234)).toBe('13.2K'); +}); +``` + +### Using Integration Tests + +Integration tests are used to test the components of your frontend code and the interaction between different components. For example, you might test that a page component renders the correct content based on certain parameters. + +Here's a simple example of an integration test for core's `Alert` component: + +```ts +import Alert from '../../../../src/common/components/Alert'; +import m from 'mithril'; +import mq from 'mithril-query'; +import { jest } from '@jest/globals'; + +describe('Alert displays as expected', () => { + it('should display alert messages with an icon', () => { + const alert = mq(m(Alert, { type: 'error' }, 'Shoot!')); + expect(alert).toContainRaw('Shoot!'); + expect(alert).toHaveElement('i.icon'); + }); + + it('should display alert messages with a custom icon when using a title', () => { + const alert = mq(Alert, { type: 'error', icon: 'fas fa-users', title: 'Woops..' }); + expect(alert).toContainRaw('Woops..'); + expect(alert).toHaveElement('i.fas.fa-users'); + }); + + it('should display alert messages with a title', () => { + const alert = mq(m(Alert, { type: 'error', title: 'Error Title' }, 'Shoot!')); + expect(alert).toContainRaw('Shoot!'); + expect(alert).toContainRaw('Error Title'); + expect(alert).toHaveElement('.Alert-title'); + }); + + it('should display alert messages with custom controls', () => { + const alert = mq(Alert, { type: 'error', controls: [m('button', { className: 'Button--test' }, 'Click me!')] }); + expect(alert).toHaveElement('button.Button--test'); + }); +}); + +describe('Alert is dismissible', () => { + it('should show dismiss button', function () { + const alert = mq(m(Alert, { dismissible: true }, 'Shoot!')); + expect(alert).toHaveElement('button.Alert-dismiss'); + }); + + it('should call ondismiss when dismiss button is clicked', function () { + const ondismiss = jest.fn(); + const alert = mq(Alert, { dismissible: true, ondismiss }); + alert.click('.Alert-dismiss'); + expect(ondismiss).toHaveBeenCalled(); + }); + + it('should not be dismissible if not chosen', function () { + const alert = mq(Alert, { type: 'error', dismissible: false }); + expect(alert).not.toHaveElement('button.Alert-dismiss'); + }); +}); +``` + +#### Methods + +These are the custom methods that are available for mithril component tests: +* **`toHaveElement(selector)`** - Checks if the component has an element that matches the given selector. +* **`toContainRaw(content)`** - Checks if the component HTML contains the given content. + +To negate any of these methods, simply prefix them with `not.`. For example, `expect(alert).not.toHaveElement('button.Alert-dismiss');`. For more information, check out the [Jest docs](https://jestjs.io/docs/using-matchers). For example you may need to check how to [mock functions](https://jestjs.io/docs/mock-functions), or how to use `beforeEach` and `afterEach` to set up and tear down tests. + + + +## E2E Tests + +Coming Soon! diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/theme.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/theme.md new file mode 100644 index 000000000..a8aa44456 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/theme.md @@ -0,0 +1,27 @@ +# Hızlı Başlangıç + +Flarum "themes" are just extensions. Typically, you'll want to use the `Frontend` extender to register custom [Less](https://lesscss.org/#overview) and JS. Of course, you can use other extenders too: for example, you might want to support settings to allow configuring your theme. + +You can indicate that your extension is a theme by setting the "extra.flarum-extension.category" key to "theme". For example: + +```json +{ + // other fields + "extra": { + "flarum-extension": { + "category": "theme" + } + } + // other fields +} +``` + +All this will do is show your extension in the "theme" section in the admin dashboard extension list. + +## Less Variable Customization + +You can define new Less variables in your extension's Less files. There currently isn't an extender to modify Less variable values in the PHP layer, but this is planned for future releases. + +## Switching Between Themes + +Flarum doesn't currently have a comprehensive system that would support switching between themes. This is planned for future releases. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/translate.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/translate.md new file mode 100644 index 000000000..f9d08d0a8 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/translate.md @@ -0,0 +1,3 @@ +# Flarum Çeviri + +**Yakında Türkçe belgeler eklenecektir.** \ No newline at end of file diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md new file mode 100644 index 000000000..7ba6adcbf --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md @@ -0,0 +1,257 @@ +# Updating For 1.0 + +Flarum version 1.0 is the long-awaited stable release! This release brings a number of refactors, cleanup, and small improvements that should make your Flarum experience just a bit better! + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Full Stack + +### Translations and transChoice + +#### Background + +Historically, Flarum has used Symfony for backend translations, and a port for frontend translations to keep format consistent. There are a few limitations to this approach though: + +- Developers need to decide between using `trans` or `transChoice` for pluralization +- The pluralization format is proprietary to Symfony +- We have to maintain the JS port ourselves +- Keys for values provided to backend translations need to be wrapped in curly braces. (e.g. `$this->translator->trans('some.translation', ['{username}' => 'Some Username!'])`). +- There's no support for complex applications (nested pluralization, non-number-based selection) +- As a result of the previous point, genderization is impossible. And that's kinda important for a lot of languages. + +### New System + +In v5, Symfony dropped their proprietary `transChoice` system in favor of the more-or-less standard [ICU MessageFormat](https://symfony.com/doc/5.2/translation/message_format.html). This solves pretty much every single one of the aforementioned issues. In this release, Flarum will be fully switching to ICU MessageFormat as well. What does this mean for extensions? + +- `transChoice` should not be used at all; instead, the variable passed for pluralization should be included in the data. +- Keys for backend translations no longer need to be surrounded by curly braces. +- Translations can now use the [`select` and `plural`](https://symfony.com/doc/5.2/translation/message_format.html) formatter syntaxes. For the `plural` formatter, the `offset` parameter and `#` magic variables are supported. +- These `select` and `plural` syntaxes can be nested to arbitrary depth. This is often a bad idea though (beyond, say, 2 levels), as things can get unnecessarily complex. + +No change to translation file naming is necessary (Symfony docs say that an `+intl-icu` suffix is necessary, but Flarum will now interpret all translation files as internationalized). + +#### Future Changes + +In the future, this will serve as a basis for additional features: + +- Translator preprocessors will allow extensions to modify arguments passed to translations. This will enable genderization (extensions could automatically extract a gender field from any objects of type "user" passed in). +- We could support internationalized "magic variables" for numbers: currently, `one` is supported, but others (`few`, `many`, etc) currently aren't. +- We could support ordinal formatting in additional to just plural formatting. + +#### Changes Needed in Extensions + +The `transChoice` methods in the frontend and backend have been removed. The `trans` method should always be used for translating, regardless of pluralization. If a translation requires pluralization, make sure you pass in the controlling variable as one of the arguments. + +In the frontend, code that looked like this: + +```js +app.translator.transChoice('some-translation', guestCount, {host: hostName}); +``` + +should be changed to: + +```js +// This uses ES6 key-property shorthand notation. {guestCount: guestCount} is equivalent to {guestCount} +app.translator.trans('some-translation', {host: hostName, guestCount }); +``` + +Similarly, in the backend, + +```php +$translator->transChoice('some-translation', $guestCount, ['{host}' => $hostName]); +``` + +should be changed to: + +```php +$translator->trans('some-translation', ['host' => $hostName, 'guestCount' => $guestCount]); +``` + +Note that in the backend, translation keys were previously wrapped in curly braces. This is no longer needed. + +#### Changes Needed in Translations + +Translations that aren't using pluralization don't need any changes. + +Pluralized translations should be changed as follows: + +`For {count} minute|For {count} minutes` + +to + +`{count, plural, one {For # minute} other {For # minutes}}` + +Note that in this example, `count` is the variable that controls pluralization. If a different variable were used (such as guestCount in the example above), this would look like: + +`{guestCount, plural, one {For # minute} other {For # minutes}}` + +See [our i18n docs](i18n.md) for more information. + +### Permissions Changes + +For a long time, the `viewDiscussions` and `viewUserList` permissions have been confusing. Despite their names: + +- `viewDiscussions` controls viewing both discussions and users. +- `viewUserList` controls searching users, not viewing user profiles. + +To clear this up, in v1.0, these permissions have been renamed to `viewForum` and `searchUsers` respectively. A migration in core will automatically adjust all permissions in the database to use the new naming. However, any extension code using the old name must switch to the new ones immediately to avoid security issues. To help the transfer, a warning will be thrown if the old permissions are referenced. + +We have also slightly improved tag scoping for permissions. Currently, permissions can be applied to tags if: + +- The permission is `viewForum` +- The permission is `startDiscussion` +- The permission starts with `discussion.` + +However, this doesn't work for namespaced permissions (`flarum-acme.discussion.bookmark`), or permissions that don't really have anything to do with discussions, but should still be scoped (e.g. `viewTag`). To counter this, a `tagScoped` attribute can be used on the object passed to [`registerPermission`](admin.md) to explicitly indicate whether the permission should be tag scopable. If this attribute is not provided, the current rules will be used to determine whether the permission should be tag scopable. + +## Frontend + +### Tooltip Changes + +The `flarum/common/components/Tooltip` component has been introduced as a simpler and less framework-dependent way to add tooltips. If your code is creating tooltips directly (e.g. via `$.tooltip()` in `oncreate` methods), you should wrap your components in the `Tooltip` component instead. For example: + +```tsx + + + +``` + +See [the source code](https://github.com/flarum/core/blob/master/js/src/common/components/Tooltip.tsx) for more examples and instructions. + +See [the PR](https://github.com/flarum/core/pull/2843/files) for examples of how to change existing code to use tooltips. + +### PaginatedListState + +The `flarum/common/states/PaginatedListState` state class has been introduced to abstract away most of the logic of `DiscussionListState` and `NotificationListState`. It provides support for loading and displaying paginated lists of JSON:API resources (usually models). In future releases, we will also provide an `PaginatedList` (or `InfiniteScroll`) component that can be used as a base class for these paginated lists. + +Please see [the source code](https://github.com/flarum/core/blob/master/js/src/common/states/PaginatedListState.ts) for a list of methods. + +Note that `flarum/forum/states/DiscussionListState`'s `empty` and `hasDiscussions` methods have been removed, and replaced with `isEmpty` and `hasItems` respectively. This is a breaking change. + +### New Loading Spinner + +The old `spin.js` based loading indicator has been replaced with a CSS-based solution. For the most part, no changes should be needed in extensions, but in some cases, you might need to update your spinner. This change also makes it easier to customize the spinner. + +See [this discussion](https://discuss.flarum.org/d/26994-beta16-using-the-new-loading-spinner) for more information. + +### classList util + +Ever wrote messy code trying to put together a list of classes for some component? Well, no longer! The [clsx library](https://www.npmjs.com/package/clsx) is now available as the `flarum/common/utils/classList` util. + +### User List + +An extensible user list has been added to the admin dashboard. In future releases, we hope to extract a generic model table component that can be used to list any model in the admin dashboard. + +See [the source code](https://github.com/flarum/core/blob/master/js/src/admin/components/UserListPage.tsx#L41) for a list of methods to extend, and examples of how columns should look like (can be added by extending the `columns` method and adding items to the [ItemList](frontend.md)). + +### Miscellaneous + +- Components should now call `super` for ALL Mithril lifecycle methods they define. Before, this was only needed for `oninit`, `onbeforeupdate`, and `oncreate`. Now, it is also needed in `onupdate`, `onbeforeremove`, and `onremove`. See [this GitHub issue](https://github.com/flarum/core/issues/2446) for information on why this change was made. +- The `flarum/common/utils/insertText` and `flarum/common/utils/styleSelectedText` utils have been moved to core from `flarum/markdown`. See `flarum/markdown` for an example of usage. +- The `extend` and `override` utils can now modify several methods at once by passing in an array of method names instead of a single method name string as the second argument. This is useful for extending the `oncreate` and `onupdate` methods at once. +- The `EditUserModal` component is no longer available through the `flarum/forum` namespace, it has been moved to `flarum/common`. Imports should be adjusted. +- The `Model` and `Route` JS extenders have been removed for now. There aren't currently used in any extensions that we know of. We will be reintroducing JS extenders during v1.x releases. +- The `Search` component can now be used with the `SearchState` state class. Previously, `SearchState` was missing the `getInitialSearch` method expected by the `Search` component. + +## Backend + +### Filesystem Extenders + +In this release, we refactored our use of the filesystem to more consistently use [Laravel's filesystem API](https://laravel.com/docs/8.x/filesystem). Extensions can now declare new disks, more easily use core's `flarum-assets` and `flarum-avatars` disks, and create their own storage drivers, enabling CDN and cloud storage support. + +### Compat and Closure Extenders + +In early Flarum versions, the `extend.php` file allowed arbitrary functions that allowed execution of arbitrary code one extension boot. For example: + +```php +return [ + // other extenders + function (Dispatcher $events) { + $events->subscribe(Listener\FilterDiscussionListByTags::class); + $events->subscribe(Listener\FilterPostsQueryByTag::class); + $events->subscribe(Listener\UpdateTagMetadata::class); + } +]; +``` + +This approach was difficult to maintain and provide a well-tested public API for, frequently resolved classes early (breaking all sorts of things), and was not very descriptive. With the extender API completed in beta 16, this approach is no longer necessary. Support for these closures has been removed in this stable version. + +One type of functionality for which the extender replacement isn't obvious is container bindings ([e.g. flarum/pusher](https://github.com/flarum/pusher/blob/v0.1.0-beta.14/extend.php#L33-L49)). This can be done with via the service provider extender (e.g. [a newer version of flarum/pusher](https://github.com/flarum/pusher/blob/master/extend.php#L40-L41)). + +If you are unsure about which extenders should be used to replace your use of callbacks in `extend.php`, or are not sure that such an extender exists, please comment so below or reach out! We're in the final stages of finishing up the extender API, so now is the time to comment. + +### Scheduled Commands + +The [fof/console](https://github.com/FriendsOfFlarum/console) library has been a popular way to schedule commands (e.g. for publishing scheduled posts, running DB-heavy operations, etc) for several release. In Flarum 1.0, this functionality has been brought into core's `Console` extender. See our [console extension documentation](console.md) for more information on how to create schedule commands, and our [console user documentation](../console.md) for more information on how to run scheduled commands. + +### Eager Loading Extender + +As part of solving [N+1 Query issues](https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/) in some [Flarum API endpoints](https://github.com/flarum/core/issues/2637), we have introduced a `load` method on the `ApiController` extender that allows you to indicate relations that should be eager loaded. + +This should be done if you know a relation will always be included, or will always be referenced by controller / permission logic. For example, we will always need the tags of a discussion to check what permissions a user has on that discussion, so we should eager load the discussion's `tags` relationship. For example: + +```php +return [ + // other extenders + (new Extend\ApiController(FlarumController\ListDiscussionsController::class)) + ->addInclude(['tags', 'tags.state', 'tags.parent']) + ->load('tags'), +]; +``` + +### RequestUtil + +The `Flarum\Http\RequestUtil`'s `getActor` and `withActor` should be used for getting/setting the actor (user) on requests. `$request->getAttribute('actor')` and `$request->withAttribute('actor')` are deprecated, and will be removed in v2.0. + +### Miscellaneous + +- The `Formatter` extender now has an `unparse` method that allows modifying XML before unparsing content. +- All route names must now be unique. In beta 16, uniqueness was enforced per-method; now, it is mandatory for all routes. +- API requests sent through `Flarum\Api\Client` now run through middleware, including `ThrottleApi`. This means that it is now possible to throttle login/registration calls. +- In beta 16, registering custom [searchers](search.md) was broken. It has been fixed in stable. +- The `post_likes` table in the [flarum/likes](https://github.com/flarum/likes) extension now logs the timestamp when likes were created. This isn't used in the extension, but could be used in other extensions for analytics. +- The `help` attribute of [admin settings](admin.md) no longer disappears on click. +- The `generate:migration` console command has been removed. The [Flarum CLI](https://discuss.flarum.org/d/26525-rfc-flarum-cli-alpha) should be used instead. +- The `GambitManager` util class is now considered internal API, and should not be used directly by extensions. +- The `session` attribute is no longer available on the `User` class. This caused issues with queue drivers, and was not conceptually correct (a user can have multiple sessions). The current session is still available via the `$request` instance. +- The `app`, `base_path`, `public_path`, `storage_path`, and `event` global helpers have been restored, but deprecated perpetually. These exist in case Laravel packages need them; they **should not** be used directly by Flarum extension code. The `flarum/laravel-helpers` package has been abandoned. +- The following deprecated features from beta 16 have been removed: + - The `TextEditor`, `TextEditorButton`, and `SuperTextarea` components are no longer exported through the `flarum/forum` namespace, but through `flarum/common` (with the exception of `SuperTextarea`, which has been replaced with `flarum/common/utils/BasicEditorDriver`). + - Support for `Symfony\Component\Translation\TranslatorInterface` has been removed, `Symfony\Contracts\Translation\TranslatorInterface` should be used instead. + - All backwards compatibility layers for the [beta 16 access token refactors](update-b16.md#access-token-and-authentication-changes) have been removed + - The `GetModelIsPrivate` event has been removed. The `ModelPrivate` extender should be used instead. + - The `Searching` (for both `User` and `Discussion` models), `ConfigureAbstractGambits`, `ConfigureDiscussionGambits`, and `ConfigureUserGambits` events have been removed. The `SimpleFlarumSearch` extender should be used instead. + - The `ConfigurePostsQuery` event has been removed. The `Filter` extender should be used instead. + - The `ApiSerializer` extender's `mutate` method has been removed. The same class's `attributes` method should be used instead. + - The `SearchCriteria` and `SearchResults` util classes have been removed. `Flarum\Query\QueryCriteria` and `Flarum\Query\QueryResults` should be used instead. + - The `pattern` property of `AbstractRegexGambit` has been removed; the `getGambitPattern` method is now a required abstract method. + - The `AbstractSearch` util class has been removed. `Flarum\Search\SearchState` and `Flarum\Filter\FilterState` should be used instead. + - The `CheckingPassword` event has been removed, the `Auth` extender should be used instead. + +## Tags Extension Changes + +As mentioned above, [tag scopable permissions](#permissions-changes) can now be explicitly declared. + +We've also made several big refactors to significantly improve tags performance. + +Firstly, the [Tag](https://github.com/flarum/tags/blob/d093ca777ba81f826157522c96680717d3a90e24/src/Tag.php#L38-L38) model's static `getIdsWhereCan` and `getIdsWhereCannot` methods have been removed. These methods scaled horribly on forums with many tags, sometimes adding several seconds to response time. + +These methods have been replaced with a `whereHasPermission` [Eloquent dynamic scope](https://laravel.com/docs/8.x/eloquent#dynamic-scopes) that returns a query. For example: + +`Tag::whereHasPermission($actor, 'viewDiscussions)`. + +That query can then be used in other DB queries, or further constricted to retrieve individual tags. + +Secondly, we no longer load in all tags as part of the initial payload. The initial payload contains all top-level primary tags, and the top 3 secondary tags. Other tags are loaded in as needed. Future releases will paginate secondary tags. This should enable forums to have thousands of secondary tags without significant performance impacts. These changes mean that extensions should not assume that all tags are available in the model store. + +## Testing Library Changes + +- Bundled extensions will not be automatically enabled; all enabled extensions must be specified in that test case. +- `setting` and `config` methods have been added that allow configuring settings and config.php values before the tested application boots. See [the testing docs](testing.md) for more information. +- The `php flarum test:setup` command will now drop the existing test DB tables before creating the database. This means that you can run `php flarum test:setup` to ensure a clean database without needing to go into the database and drop tables manually. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md new file mode 100644 index 000000000..ed17364ed --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md @@ -0,0 +1,139 @@ +# Updating For 1.x + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## 1.7 + +### Frontend + +- Frontend extenders similar to the backend have been added, we highly recommend using them instead of the old method (https://docs.flarum.org/extend/models#adding-new-models-1), (https://docs.flarum.org/extend/routes#frontend-routes). +- There is a new tag selection component (https://github.com/flarum/framework/blob/360a2ba1d886df3fc6d326be932c5431ee9df8cf/extensions/tags/js/src/common/components/TagSelectionModal.tsx). + +### Backend + +- Support for php 8.2, deprecations are still thrown by some packages, the testing workflow has been updated to ignore deprecations on 8.2 +- The `/api` endpoint now contains the actor as an included relationship. +- The `Model::dateAttribute($attribute)` extender is deprecated, use `Model::cast($attribute, 'datetime')` instead. + +### Tooling + +- New `phpstan` package to run static code analysis on your extensions for code safety (https://docs.flarum.org/extend/static-code-analysis). +- New `jest-config` package to run frontend unit and component tests (https://docs.flarum.org/extend/testing). + +## 1.6 Changes + +### Backend + +- Added customizable session drivers through the `Session` extender. + +## 1.5 Changes + +### Frontend + +- More portions of the frontend are now written in TypeScript, providing a better extension development experience. +- Modals can be used in stacks, allowing for multiple modals to be open at once. This is useful for modals that open other modals: `app.modal.show(ModalComponent, { attrs }, true)`. + +### Backend + +- There is a new `createTableIfNotExists` migration helper, which can be used to create tables only if they don't already exist. + +## 1.4 Changes + +No developer-facing changes were made in Flarum v1.4. + +## 1.3 Changes + +Flarum v1.3 included mostly QoL improvements. Below are listed note worthy changes for extension developers: + +### Frontend + +- More portions of the frontend are now written in TypeScript, providing a better extension development experience. +- Frontend errors will no longer cause the forum to crash into a NoJs page. The extension will fail to execute its frontend code (initializer) and display an error to the admin through an alert, and to all users through the console. The frontend will continue to execute without the extension's frontend changes. +- The markdown toolbar can now be used on the admin side. + +### Backend + +- Calculation of the `number` attribute on `posts` has changed and no longer relies on the discussion model's `post_number_index` attribute which is now deprecated and will be removed in 2.0 +- Extension event listeners are now added after core even listeners, this should generally cause no changes in behavior. + +### Tooling + +- The backend tests workflow now automatically fails tests if there are any PHP warnings and notices. + +## 1.2 Changes + +Flarum v1.2 included quite a few bugfixes, internal refactors, and new features. The following recaps the most important changes for extension developers: + +### Frontend + +- Flarum core now passes TypeScript type checking (on the portion written in TypeScript). Additionally, major portions of the frontend (models, the application instance, and others) are now written in TypeScript. These changes should make it much easier and more fruitful to write extensions in TypeScript. +- Instead of directly using Less variables in CSS code, core now uses CSS variables. For the most part, we've just created CSS variables and set their values to the Less variables. This should make theming and customizing CSS a lot easier. https://github.com/flarum/core/pull/3146. +- Dropdowns can now be lazy-drawn to improve performance. You can do this by setting the lazy draw attr to "true". https://github.com/flarum/core/pull/2925. +- [Textarea-type settings](https://github.com/flarum/core/pull/3141) are now supported through the `app.extensionData.registerSetting` util. +- You can now use Webpack 5 to bundle your extension's code. This will offer minor bundle size improvements. +- A new `flarum/common/components/ColorPreviewInput` component [has been added](https://github.com/flarum/core/pull/3140). It can be used directly, or through the `color-preview` type when registered via `app.extensionData.registerSetting`. +- Extensions can now [modify the minimum search length](https://github.com/flarum/core/pull/3130) of the `Search` component. +- The following components are now extensible: + - The "colors" part of the Appearance page in the admin dashboard: https://github.com/flarum/core/pull/3186 + - The `StatusWidget` dropdown in the admin dashboard: https://github.com/flarum/core/pull/3189 + - `primaryControls` in the notification list: https://github.com/flarum/core/pull/3204 +- Extensions now have finer control over positioning when adding elements to the DiscussionPage sidebar items: https://github.com/flarum/core/pull/3165 +- + +### Backend + +- An [extender for settings defaults](https://github.com/flarum/core/pull/3127) has been added. This should be used instead of the `addSettings` migration helper, which has been deprecated. +- You can now [generate Less variables from setting values](https://github.com/flarum/core/pull/3011) via the `Settings` extender. +- Extensions can now [override/supplement blade template namespaces](https://github.com/flarum/core/pull/3167) through the `View` extender, meaning custom blade templates can be used instead of the default ones added by core or extensions. +- You can now define [custom Less functions through PHP](https://github.com/flarum/core/pull/3190), allowing you to use some backend logic in your Less theming. +- Extensions can now create [custom page title drivers](https://github.com/flarum/core/pull/3109/files) for titles in server-returned HTML. +- Custom logic can now be used when [deciding which relations to eager-load](https://github.com/flarum/core/pull/3116). +- Events [are now dispatched](https://github.com/flarum/core/pull/3203) for the `Notification\Read` and `Notification\ReadAll` events. +- An `ImageManager` instance is now [bound into the container](https://github.com/flarum/core/pull/3195), and can be configured to use either the `gd` or `imagick` backing drivers via the `"intervention.driver"` key in `config.php`. +- User IP addresses are now passed to the [API Client](https://github.com/flarum/core/pull/3124). +- A custom revision versioner implentation [can be set via container bindings](https://github.com/flarum/core/pull/3183) to customize how asset versions are named. +- A SlugManager instance [is now available](https://github.com/flarum/core/pull/3194) in blade templates via the `slugManager` variable. + +### Misc + +- Translations now support the `zero`, `one`, `two`, `few`, and `many` localized plural rules for `plural` ICU MessageFormat translations. This was done through the [`Intl.PluralRules` helper](https://github.com/flarum/core/issues/3072). +- Translations are now used for page titles, so that the format can be customized via language packs or [Linguist](https://discuss.flarum.org/d/7026-linguist-customize-translations-with-ease): https://github.com/flarum/core/pull/3077, https://github.com/flarum/core/pull/3228 +- API endpoints for retrieving single groups, as well as support for filtering groups on the plural get endpoint, [have been added](https://github.com/flarum/core/pull/3084). + + +### Tooling + + +- The `flarum-cli infra` command can now be used to update or enable various infrastructure features. You can now add the following to your extension in just one command: + - TypeScript + - Prettier for JS/TS formatting + - Backend testing with PHPUnit + - Code formatting with StyleCI + - EditorConfig support + - GitHub actions for automating testing, linting, type checking, and building. +- You can also exclude any files from these updates by adding their relative path to the "extra.flarum-cli" key's array in your extension's `composer.json` file. For example, if you wanted to exclude your tsconfig file from any updates by the infra system, the "extra.flarum-cli" key's value should be `["js/tsconfig.json"]`. +- The `flarum-cli audit infra` can be used to check that all infra modules your extension uses are up to date. The `--fix` flag can be used to automatically fix any issues, which has essentially the same effect as running `flarum-cli infra` for each outdated module. +- All `flarum-cli` commands can now be run with a `--no-interaction` flag to prevent prompts. Defaults will be used when possible, and errors will be thrown if a prompt is needed and there is no default. +- Frontend GH actions now support type-checking, as well as type coverage reports. + +## 1.1 Changes + +Flarum version 1.1 mostly focuses on bugfixes and quality-of-life improvements following our stable release earlier this year. These are mainly user-facing and internal infrastructure changes, so extensions are not significantly affected. + +### Frontend + +- Flarum now has an organization-wide prettier config package under [`@flarum/prettier-config`](https://github.com/flarum/prettier-config). +- Most custom (setting or data based) coloring in core is now done via [CSS custom properties](https://github.com/flarum/core/pull/3001). +- Typehinting for Flarum's globals are now [supported in extensions](https://github.com/flarum/core/pull/2992). +- You can now pass extra attrs to the `Select` component, and they will be [passed through to the DOM](https://github.com/flarum/core/pull/2959). +- The `DiscussionPage` component is now organized [as an item list](https://github.com/flarum/core/pull/3004), so it's easier for extensions to change its content. +- Extensions [can now edit](https://github.com/flarum/core/pull/2935) the `page` parameter of `PaginatedListState`. + +### Backend + +- Flarum now comes with a [Preload extender](https://github.com/flarum/core/pull/3057) for preloading any custom frontend assets. +- A new [Theme](https://github.com/flarum/core/pull/3008) extender now allows overriding Less files and internal imports. This allows themes to more easily completely replace Less modules. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md new file mode 100644 index 000000000..9f2353ff9 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md @@ -0,0 +1,53 @@ +# Beta 10 için Güncelleme + +Beta 10 further solidifies the core architecture, offering new extenders as a stable, use-case-driven API for extending Flarum's core. A few small changes may necessitate updates to your extensions to make them compatible with Beta 10. These are detailed below. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Breaking Changes + +- The `Flarum\Event\GetDisplayName` class has been moved to `Flarum\User\Event\GetDisplayName`. +- The `Flarum\Http\Exception\ForbiddenException` has been removed. Use `Flarum\User\Exception\PermissionDeniedException` instead. +- The `assertGuest()` method of the `Flarum\User\AssertPermissionTrait` has been removed without replacement. +- Old error handling middleware and exception handler classes were removed (see "New Features" for more details): + - `Flarum\Api\Middleware\HandleErrors` + - `Flarum\Http\Middleware\HandleErrorsWithView` + - `Flarum\Http\Middleware\HandleErrorsWithWhoops` + - `Flarum\Api\ErrorHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + - `Flarum\Api\ExceptionHandler\FloodingExceptionHandler` + - `Flarum\Api\ExceptionHandler\IlluminateValidationExceptionHandler` + - `Flarum\Api\ExceptionHandler\InvalidAccessTokenExceptionHandler` + - `Flarum\Api\ExceptionHandler\InvalidConfirmationTokenExceptionHandler` + - `Flarum\Api\ExceptionHandler\MethodNotAllowedExceptionHandler` + - `Flarum\Api\ExceptionHandler\ModelNotFoundExceptionHandler` + - `Flarum\Api\ExceptionHandler\PermissionDeniedExceptionHandler` + - `Flarum\Api\ExceptionHandler\RouteNotFoundExceptionHandler` + - `Flarum\Api\ExceptionHandler\TokenMismatchExceptionHandler` + - `Flarum\Api\ExceptionHandler\ValidationExceptionHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + +## Recommendations + +- We tweaked the [recommended flarum/core version constraints for extensions](start.md#composer-json). We now recommend you mark your extension as compatible with the current and the upcoming beta release. (For beta.10, that would be any beta.10.x and beta.11.x version.) The core team will strive to make this work well by deprecating features before removing them. More details on this change in [this pull request](https://github.com/flarum/docs/pull/75). + +## New Features + +- New, extensible **error handling** stack in the `Flarum\Foundation\ErrorHandling` namespace: The `Registry` maps exceptions to "types" and HTTP status codes, `HttpFormatter` instances turn them into HTTP responses. Finally, `Reporter` instances are notified about unknown exceptions. + - You can build custom exception classes that will abort the current request (or console command). If they have semantic meaning to your application, they should implement the `Flarum\Foundation\KnownError` interface, which exposes a "type" that is used to render pretty error pages or dedicated error messages. + - More consistent use of HTTP 401 and 403 status codes. HTTP 401 should be used when logging in (i.e. authenticating) could make a difference; HTTP 403 is reserved for requests that fail because the already authenticated user is lacking permissions to do something. + - The `assertRegistered()` and `assertPermission()` methods of the `Flarum\User\AssertPermissionTrait` trait have been changed to match above semantics. See [this pull request](https://github.com/flarum/core/pull/1854) for more details. + - Error views are now determined based on error "type", not on status code (see [bdac88b](https://github.com/flarum/core/commit/bdac88b5733643b9c5dabae9e09a64d9f6e41d58)) +- **Queue support**: This release incorporates Laravel's illuminate/queue package, which allows offloading long-running tasks (such as email sending or regular cleanup jobs) onto a dedicated worker process. These changes are mostly under the hood, the next release(s) will start using the queue system for sending emails. By default, Flarum will use the "sync" queue driver, which executes queued tasks immediately. This is far from ideal and mostly guarantees a hassle-free setups. Production-grade Flarum installs are expected to upgrade to a more full-featured queue adapter. +- The `Flarum\Extend\LanguagePack` now accepts an optional path in its constructor. That way, language packs can store their locales in a different directory if they want to. +- The `formatContent()` method of `Flarum\Post\CommentPost` can now be called without an HTTP request instance, e.g. when rendering a post in an email template. + +## Deprecations + +- **Reminder**: In previous versions of Flarum, an extensions' main file was named `bootstrap.php`. This name will no longer be supported in the stable 0.1 release. Make sure your extension uses the name `extend.php`. +- Laravel's global string and array helpers (e.g. `str_contains()` and `array_only()`) are deprecated in favor of their class based alternatives (`Illuminate\Support\Str::contains()` and `Illuminate\Support\Arr::only()`). See the [announcement](https://laravel-news.com/laravel-5-8-deprecates-string-and-array-helpers) and [pull request](https://github.com/laravel/framework/pull/26898) for more information. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md new file mode 100644 index 000000000..6fae49b97 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md @@ -0,0 +1,34 @@ +# Beta 12 için Güncelleme + +Beta 12 packs several new features for extension developers, but also continues our cleanup efforts which results in a few changes, so please read this guide carefully to find out whether your extensions are affected. We invested extra effort to introduce new functionality in a backward-compatible manner or first deprecate functionality before it will be removed in the next release, in line with our [versioning recommendations](start.md#composer-json). + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Deprecations / Upcoming breaking changes + +- **Reminder**: In previous versions of Flarum, an extensions' main file was named `bootstrap.php`. This name will no longer be supported in the stable 0.1 release. Make sure your extension uses the name `extend.php`. +- PHP 7.1 support will be dropped in beta.13. +- Using library classes from the `Zend` namespace is now deprecated and will be removed in beta.13. Use the `Laminas` namespace instead. See [PR #1963](https://github.com/flarum/core/pull/1963). +- The `Flarum\Util\Str::slug()` method has been deprecated. Use `Illuminate\Support\Str::slug()` instead. +- The `Flarum\Event\ConfigureMiddleware` has been deprecated. We finally have a [proper replacement](middleware.md) - see "New Features" below. Therefore, it will be removed in beta.13. +- If you implement the `Flarum\Mail\DriverInterface`: + - Returning a plain array of field names from the `availableSettings()` method is deprecated, but still supported. It must now return an array of field names mapping to their type. See [the inline documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L25-L32) for more details. + - Implement the `validate()` method that will be required in beta.13. See [its documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L34-L48). + - Implement the `canSend()` method that will be required in beta.13. See [its documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L50-L54). + +## New Features + +- New **PHP extenders**: + - `Flarum\Extend\Middleware` offers methods for adding, removing or replacing middleware in our three middleware stacks (api, forum, admin). We also added [documentation](middleware.md) for this feature. + - `Flarum\Extend\ErrorHandling` lets you configure status codes and other aspects of our error handling stack depending on error types or exception classes. +- **JavaScript**: + - The `flarum/components/Select` component now supports a `disabled` prop. See [PR #1978](https://github.com/flarum/core/pull/1978). + +## Other changes / Recommendations + +- The `TextFormatter` library has been updated to (at least) version 2.3.6. If you are using it (likely through our own `Flarum\Formatter\Formatter` class), we recommend scanning [the library's changelog](https://github.com/s9e/TextFormatter/blob/2.3.6/CHANGELOG.md). +- The JS `slug()` helper from the `flarum/utils/string` module should only be used to *suggest* slugs to users, not enforce them. It does not employ any sophisticated transliteration logic like its PHP counterpart. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md new file mode 100644 index 000000000..19d0c18d8 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md @@ -0,0 +1,40 @@ +# Beta 13 için Güncelleme + +Beta 13 ships with several new extenders to simplify building and maintaining extensions. We do our best to create backward compatibility changes. We recommend changing to new Extenders as soon as they are available. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Breaking Changes + +- Dropped support for PHP 7.1. +- Classes from the `Zend` namespace are now removed. Use the `Laminas` namespace instead. See [PR #1963](https://github.com/flarum/core/pull/1963). +- The `Flarum\Util\Str::slug()` method has been removed including the class. Use `Illuminate\Support\Str::slug()` instead. +- The `Flarum\Event\ConfigureMiddleware` has been removed. Use the [proper replacement](middleware.md). +- Several events used in Event Listeners have been removed, use their [replacement extender](start.md#extenders) instead. +- The LanguagePack extender only loads keys from extensions that are enabled. The translations loaded are based on the yaml files matching the [i18n namespace](i18n.md#appendix-a-standard-key-format). +- All notifications are now sent through the queue; without a queue driver they will run as usual. +- The implementation of avatar upload changed, we're [no longer storing files temporarily on disk](https://github.com/flarum/core/pull/2117). +- The SES mail driver [has been removed](https://github.com/flarum/core/pull/2011). +- Mail driver backward compatibility from beta 12 has been removed, use the new Mail extender or implement the [modified interface](https://github.com/flarum/core/blob/master/src/Mail/DriverInterface.php). + +## Recommendations + +- Beta 14 will ship with a rewrite in the frontend (javascript). If you're building for that release, make sure to follow our [progress](https://github.com/flarum/core/pull/2126). + +## New Features + +- A ton of new extenders: + - [Middleware extender](https://github.com/flarum/core/pull/2017) + - [Console extender](https://github.com/flarum/core/pull/2057) + - [CSRF extender](https://github.com/flarum/core/pull/2095) + - [Event extender](https://github.com/flarum/core/pull/2097) + - [Mail extender](https://github.com/flarum/core/pull/2012) + - [Model extender](https://github.com/flarum/core/pull/2100) + +## Deprecations + +- Several events [have been marked deprecated](https://github.com/flarum/core/commit/4efdd2a4f2458c8703aae654f95c6958e3f7b60b) to be removed in beta 14. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md new file mode 100644 index 000000000..bee912ac2 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md @@ -0,0 +1,757 @@ +# Beta 14 için Güncelleme + +This release brings a large chunk of breaking changes - hopefully the last chunk of this size before our stable release. In order to prepare the codebase for the upcoming stable release, we decided it was time to modernize / upgrade / exchange some of the underlying JavaScript libraries that are used in the frontend. Due to the nature and size of these upgrades, we have to pass on some of the breaking changes to you, our extension developers. + +On the bright side, this overdue upgrade brings us closer to the conventions of best practices of [Mithril.js](https://mithril.js.org/), the mini-framework used for Flarum's UI. Mithril's 2.0 release sports a more consistent component interface, which should be a solid foundation for years to come. Where possible, we replicated old APIs, to ease the upgrade and give you time to do the full transition. Quite a few breaking changes remain, though - read more below. + +:::tip + +If you need help with the upgrade, our friendly community will gladly help you out either [on the forum](https://discuss.flarum.org/t/extensibility) or [in chat](https://flarum.org/chat/). + +::: + +To ease the process, we've clearly separated the changes to the [frontend (JS)](#frontend-javascript) from those in the [backend (PHP)](#backend-php) below. If your extension does not change the UI, consider yourself lucky. :-) + +A [summary of the frontend changes](#required-frontend-changes-recap) is available towards the end of this guide. + +## Frontend (JavaScript) + +### Mithril 2.0: Concepts + +Most breaking changes required by beta 14 are prompted by changes in Mithril 2. [Mithril's upgrade guide](https://mithril.js.org/migration-v02x.html) is an extremely useful resource, and should be consulted for more detailed information. A few key changes are explained below: + +#### props -> attrs; initProps -> initAttrs + +Props passed into component are now referred to as `attrs`, and can be accessed via `this.attrs` where you would prior use `this.props`. This was done to be closer to Mithril's preferred terminology. We have provided a temporary backwards compatibility layer for `this.props`, but recommend using `this.attrs`. + +Accordingly, `initProps` has been replaced with `initAttrs`, with a similar BC layer. + +#### m.prop -> `flarum/utils/Stream` + +Mithril streams, which were available via `m.prop` in Mithril 0.2, are now available via `flarum/utils/Stream`. `m.prop` will still work for now due to a temporary BC layer. + +#### m.withAttr -> withAttr + +The `m.withAttr` util has been removed from Mithril. We have provided `flarum/utils/withAttr`, which does the same thing. A temporary BC layer has been added for `m.withAttr`. + +#### Lifecycle Hooks + +In mithril 0.2, we had 2 "lifecycle hooks": + +`init`, an unofficial hook which ran when the component instance was initialized. + +`config`, which ran when components were created, and on every redraw. + + +Mithril 2 has the following hooks; each of which take `vnode` as an argument: + +- `oninit` +- `oncreate` +- `onbeforeupdate` +- `onupdate` +- `onbeforeremove` +- `onremove` + +Please note that if your component is extending Flarum's helper `Component` class, you must call `super.METHOD(vnode)` if using `oninit`, `oncreate`, and `onbeforeupdate`. + +More information about what each of these do can be found [in Mithril's documentation](https://mithril.js.org/lifecycle-methods.html). + +A trivial example of how the old methods map to the new is: + +```js +class OldMithrilComponent extends Component { + init() { + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + config(element, isInitialized) { + console.log('Code to run on every redraw AND when the element is first attached'); + + if (isInitialized) return; + + console.log('Code to execute only once when components are first created and attached to the DOM'); + + context.onunload = () => { + console.log('Code to run when the component is removed from the DOM'); + } + } + + view() { + // In mithril 0, you could skip redrawing a component (or part of a component) by returning a subtree retain directive. + // See https://mithril.js.org/archive/v0.2.5/mithril.render.html#subtree-directives + // dontRedraw is a substitute for logic; usually, this is used together with SubtreeRetainer. + if (dontRedraw()) return { subtree: 'retain' }; + + return

Hello World!

; + } +} + +class NewMithrilComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + oncreate(vnode) { + super.oncreate(vnode); + + console.log('Code to run when components are first created and attached to the DOM'); + } + + onbeforeupdate(vnode, oldVnode) { + super.onbeforeupdate(vnode); + + console.log('Code to run BEFORE diffing / redrawing components on every redraw'); + + // In mithril 2, if we want to skip diffing / redrawing a component, we return "false" in its onbeforeupdate lifecycle hook. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeupdate + // This is also typically used with SubtreeRetainer. + if (dontRedraw()) return false; + } + + onupdate(vnode) { + // Unlike config, this does NOT run when components are first attached. + // Some code might need to be replicated between oncreate and onupdate. + console.log('Code to run on every redraw AFTER the DOM is updated.'); + } + + onbeforeremove(vnode) { + // This is run before components are removed from the DOM. + // If a promise is returned, the DOM element will only be removed when the + // promise completes. It is only called on the top-level component that has + // been removed. It has no equivalent in Mithril 0.2. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeremove + return Promise.resolve(); + } + + onremove(vnode) { + console.log('Code to run when the component is removed from the DOM'); + } +} +``` + +#### Children vs Text Nodes + +In Mithril 0.2, every child of a vnode is another vnode, stored in `vnode.children`. For Mithril 2, as a performance optimization, vnodes with a single text child now store that text directly in `vnode.text`. For developers, that means that `vnode.children` might not always contain the results needed. Luckily, text being stored in `vnode.text` vs `vnode.children` will be the same each time for a given component, but developers should be aware that at times, they might need to use `vnode.text` and not `vnode.children`. + +Please see [the mithril documentation](https://mithril.js.org/vnodes.html#structure) for more information on vnode structure. + +#### Routing API + +Mithril 2 introduces a few changes in the routing API. Most of these are quite simple: + +- `m.route()` to get the current route has been replaced by `m.route.get()` +- `m.route(NEW_ROUTE)` to set a new route has been replaced by `m.route.set(NEW_ROUTE)` +- When registering new routes, a component class should be provided, not a component instance. + +For example: + +```js +// Mithril 0.2 +app.routes.new_page = { path: '/new', component: NewPage.component() } + +// Mithril 2.0 +app.routes.new_page = { path: '/new', component: NewPage } +``` + +Additionally, the preferred way of defining an internal (doesn't refresh the page when clicked) link has been changed. The `Link` component should be used instead. + +```js +// Mithril 0.2 +
Link Content + +// Mithril 2 +import Link from 'flarum/components/Link'; + +Link Content +``` + +You can also use `Link` to define external links, which will just render as plain `Children` html links. + +For a full list of routing-related changes, please see [the mithril documentation](https://mithril.js.org/migration-v02x.html). + +#### Redraw API + +Mithril 2 introduces a few changes in the redraw API. Most of these are quite simple: + +- Instead of `m.redraw(true)` for synchronous redraws, use `m.redraw.sync()` +- Instead of `m.lazyRedraw()`, use `m.redraw()` + +Remember that Mithril automatically triggers a redraw after DOM event handlers. The API for preventing a redraw has also changed: + +```js +// Mithril 0.2 + + +// Mithril 2 + +``` + +#### AJAX + +The `data` parameter of `m.request({...})` has been split up into `body` and `params`. + +For examples and other AJAX changes, see [the mithril documentation](https://mithril.js.org/migration-v02x.html#mrequest). + +#### Promises + +`m.deferred` has been removed, native promises should be used instead. For instance: + +```js +// Mithril 0.2 +const deferred = m.deferred(); + +app.store.find('posts').then(result => deferred.resolve(result)); + +return deferred.promise; + +// Mithril 2 +return app.store.find('posts'); +``` + +#### Component instances should not be stored + +Due to optimizations in Mithril's redrawing algorithms, [component instances should not be stored](https://mithril.js.org/components.html#define-components-statically,-call-them-dynamically). + +So whereas before, you might have done something like: + +```js +class ChildComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return

{this.counter}

; + } +} +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.child = new ChildComponent(); + } + + view() { + return ( +
+ + {this.child.render()} +
+ ) + } +} +``` + +That will no longer work. In fact; the Component class no longer has a render method. + +Instead, any data needed by a child component that is modified by a parent component should be passed in as an attr. For instance: + +```js +class ChildComponent extends Component { + view() { + return

{this.attrs.counter}

; + } +} + +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return ( +
+ + +
+ ) + } +} +``` + +For more complex components, this might require some reorganization of code. For instance, let's say you have data that can be modified by several unrelated components. In this case, it might be preferable to create a POJO "state instance' for this data. These states are similar to "service" singletons used in Angular and Ember. For instance: + +```js +class Counter { + constructor() { + this._counter = 0; + } + + increaseCounter() { + this._counter += 1; + } + + getCount() { + return this._counter; + } +} + +app.counter = new Counter(); + +extend(HeaderSecondary.prototype, 'items', function(items) { + items.add('counterDisplay', +
+

Counter: {app.counter.getCount()}

+
+ ); +}) + +extend(HeaderPrimary.prototype, 'items', function(items) { + items.add('counterButton', +
+ +
+ ); +}) +``` + +This "state pattern" can be found throughout core. Some non-trivial examples are: + +- PageState +- SearchState and GlobalSearchState +- NotificationListState +- DiscussionListState + +### Changes in Core + +#### Modals + +Previously, modals could be opened by providing a `Modal` component instance: + +```js +app.modal.show(new LoginModal(identification: 'prefilledUsername')); +``` + +Since we don't store component instances anymore, we pass in the component class and any attrs separately. + +```js +app.modal.show(LoginModal, {identification: 'prefilledUsername'}); +``` + +The `show` and `close` methods are still available through `app.modal`, but `app.modal` now points to an instance of `ModalManagerState`, not of the `ModalManager` component. Any modifications by extensions should accordingly be done to `ModalManagerState`. + +#### Alerts + +Previously, alerts could be opened by providing an `Alert` component instance: + +```js +app.alerts.show(new Alert(type: 'success', children: 'Hello, this is a success alert!')); +``` + +Since we don't store component instances anymore, we pass in a component class, attrs, children separately. The `show` method has 3 overloads: + +```js +app.alerts.show('Hello, this is a success alert!'); +app.alerts.show({type: 'success'}, 'Hello, this is a success alert!'); +app.alerts.show(Alert, {type: 'success'}, 'Hello, this is a success alert!'); +``` + +Additionally, the `show` method now returns a unique key, which can then be passed into the `dismiss` method to dismiss that particular alert. This replaces the old method of passing the alert instance itself to `dismiss`. + +The `show`, `dismiss`, and `clear` methods are still available through `app.alerts`, but `app.alerts` now points to an instance of `AlertManagerState`, not of the `AlertManager` component. Any modifications by extensions should accordingly be done to `AlertManagerState`. + +#### Composer + +Since we don't store a component instances anymore, a number of util methods from `Composer`, `ComposerBody` (and it's subclasses), and `TextEditor` have been moved onto `ComposerState`. + +For `forum/components/Composer`, `isFullScreen`, `load`, `clear`, `show`, `hide`, `close`, `minimize`, `fullScreen`, and `exitFullScreen` have been moved to `forum/states/ComposerState`. They all remain accessible via `app.composer.METHOD` + +A `bodyMatches` method has been added to `forum/states/ComposerState`, letting you check whether a certain subclass of `ComposerBody` is currently open. + +Various input fields are now stored as [Mithril Streams](https://mithril.js.org/stream.html) in `app.composer.fields`. For instance, to get the current composer content, you could use `app.composer.fields.content()`. Previously, it was available on `app.composer.component.content()`. **This is a convention that `ComposerBody` subclasses that add inputs should follow.** + +`app.composer.component` is no longer available. + +- Instead of `app.composer.component instanceof X`, use `app.composer.bodyMatches(X)`. +- Instead of `app.composer.component.props`, use `app.composer.body.attrs`. +- Instead of `app.composer.component.editor`, use `app.composer.editor`. + +For `forum/components/TextEditor`, the `setValue`, `moveCursorTo`, `getSelectionRange`, `insertAtCursor`, `insertAt`, `insertBetween`, `replaceBeforeCursor`, `insertBetween` methods have been moved to `forum/components/SuperTextarea`. + +Also for `forum/components/TextEditor`, `this.disabled` is no longer used; `disabled` is passed in as an attr instead. It may be accessed externally via `app.composer.body.attrs.disabled`. + +Similarly to Modals and Alerts, `app.composer.load` no longer accepts a component instance. Instead, pass in the body class and any attrs. For instance, + +```js +// Mithril 0.2 +app.composer.load(new DiscussionComposer({user: app.session.user})); + +// Mithril 2 +app.composer.load(DiscussionComposer, {user: app.session.user}) +``` + +Finally, functionality for confirming before unloading a page with an active composer has been moved into the `common/components/ConfirmDocumentUnload` component. + +#### Widget and DashboardWidget + +The redundant `admin/components/Widget` component has been removed. `admin/components/DashboardWidget` should be used instead. + +#### NotificationList + +For `forum/components/NotificationList`, the `clear`, `load`, `loadMore`, `parseResults`, and `markAllAsRead` methods have been moved to `forum/states/NotificationListState`. + +Methods for `isLoading` and `hasMoreResults` have been added to `forum/states/NotificationListState`. + +`app.cache.notifications` is no longer available; `app.notifications` (which points to an instance of `NotificationListState`) should be used instead. + +#### Checkbox + +Loading state in the `common/components/Checkbox` component is no longer managed through `this.loading`; it is now passed in as a prop (`this.attrs.loading`). + +#### Preference Saver + +The `preferenceSaver` method of `forum/components/SettingsPage` has been removed without replacement. This is done to avoid saving component instances. Instead, preferences should be directly saved. For instance: + +```js +// Old way +Switch.component({ + children: app.translator.trans('core.forum.settings.privacy_disclose_online_label'), + state: this.user.preferences().discloseOnline, + onchange: (value, component) => { + this.user.pushAttributes({ lastSeenAt: null }); + this.preferenceSaver('discloseOnline')(value, component); + }, +}) + +// Without preferenceSaver +Switch.component({ + children: app.translator.trans('core.forum.settings.privacy_disclose_online_label'), + state: this.user.preferences().discloseOnline, + onchange: (value) => { + this.discloseOnlineLoading = true; + + this.user.savePreferences({ discloseOnline: value }).then(() => { + this.discloseOnlineLoading = false; + m.redraw(); + }); + }, + loading: this.discloseOnlineLoading, +}) +``` + +A replacement will eventually be introduced. + +#### DiscussionListState + +For `forum/components/DiscussionList`, the `requestParams`, `sortMap`, `refresh`, `loadResults`, `loadMore`, `parseResults`, `removeDiscussion`, and `addDiscussion` methods have been moved to `forum/states/DiscussionListState`. + +Methods for `hasDiscussions`, `isLoading`, `isSearchResults`, and `empty` have been added to `forum/states/DiscussionListState`. + +`app.cache.discussions` is no longer available; `app.discussions` (which points to an instance of `DiscussionListState`) should be used instead. + +#### PageState + +`app.current` and `app.previous` no longer represent component instances, they are now instances of the `common/states/PageState` class. This means that: + +- Instead of `app.current instanceof X`, use `app.current.matches(X)` +- Instead of `app.current.PROPERTY`, use `app.current.get('PROPERTY')`. Please note that all properties must be exposed EXPLICITLY via `app.current.set('PROPERTY', VALUE)`. + +#### PostStream + +Logic from `forum/components/PostStreamScrubber`'s `update` method has been moved to `forum/components/PostStream`'s `updateScrubber` method. + +For `forum/components/PostStream`, the `update`, `goToFirst`, `goToLast`, `goToNumber`, `goToIndex`, `loadNearNumber`, `loadNearIndex`, `loadNext`, `loadPrevious`, `loadPage`, `loadRange`, `show`, `posts`, `reset`, `count`, and `sanitizeIndex` methods have been moved to `forum/states/PostStreamState`. + +Methods for `disabled` and `viewingEnd` have been added to `forum/states/PostStreamState`. + +#### SearchState and GlobalSearchState + +As with other components, we no longer store instances of `forum/components/Search`. As such, every `Search` component instance should be paired with a `forum/states/SearchState` instance. + +At the minimum, `SearchState` contains the following methods: + +- getValue +- setValue +- clear +- cache (adds a searched value to cache, meaning that we don't need to search for its results again) +- isCached (checks if a value has been searched for before) + +All of these methods have been moved from `Search` to `SearchState`. Additionally, Search's `stickyParams`, `params`, `changeSort`, `getInitialSearch`, and `clearInitialSearch` methods have been moved to `forum/states/GlobalSearchState`, which is now available via `app.search`. + +To use a custom search, you'll want to: + +1. Possibly create a custom subclass of `SearchState` +2. Create a custom subclass of `Search`, which overrides the `selectResult` method to handle selecting results as needed by your use case, and modify the `sourceItems` methods to contain the search sources you need. + +#### moment -> dayjs + +The `moment` library has been removed, and replaced by the `dayjs` library. The global `moment` can still be used for now, but is deprecated. `moment` and `dayjs` have very similar APIs, so very few changes will be needed. Please see the dayjs documentation [for more information](https://day.js.org/en/) on how to use it. + +#### Subtree Retainer + +`SubtreeRetainer` is a util class that makes it easier to avoid unnecessary redraws by keeping track of some pieces of data. When called, it checks if any of the data has changed; if not, it indicates that a redraw is not necessary. + +In mithril 0.2, its `retain` method returned a [subtree retain directive](https://mithril.js.org/archive/v0.1.25/mithril.render.html#subtree-directives) if no redraw was necessary. + +In mithril 2, we use its `needsRebuild` method in combination with `onbeforeupdate`. For instance: + +```js +class CustomComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + this.showContent = false; + + this.subtree = new SubtreeRetainer( + () => this.showContent, + ) + } + + onbeforeupdate() { + // If needsRebuild returns true, mithril will diff and redraw the vnode as usual. Otherwise, it will skip this redraw cycle. + // In this example, this means that this component and its children will only be redrawn when extra content is toggled. + return this.subtree.needsRebuild(); + } + + view(vnode) { + return
+ +

Hello World!{this.showContent ? ' Extra Content!' : ''}

+
; + } +} +``` + +#### attrs() method + +Previously, some components would have an attrs() method, which provided an extensible way to provide attrs to the top-level child vnode returned by `view()`. For instance, + +```js +class CustomComponent extends Component { + view() { + return

Hello World!

; + } + + attrs() { + return { + className: 'SomeClass', + onclick: () => console.log('click'), + }; + } +} +``` + +Since `this.attrs` is now used for attrs passed in from parent components, `attrs` methods have been renamed to `elementAttrs`. + +#### Children and .component + +Previously, an element could be created with child elements by passing those in as the `children` prop: + +```js +Button.component({ + className: 'Button Button--primary', + children: 'Button Text' +}); +``` + +This will no longer work, and will actually result in errors. Instead, the 2nd argument of the `component` method should be used: + +```js +Button.component({ + className: 'Button Button--primary' +}, 'Button Text'); +``` + +Children can still be passed in through JSX: + +```js + +``` + +#### Tag attr + +Because mithril uses 'tag' to indicate the actual html tag (or component class) used for a vnode, you can no longer pass `tag` as an attr to components extending Flarum's `Component` helper class. The best workaround here is to just use another name for this attr. + +#### affixSidebar + +The `affixSidebar` util has been removed. Instead, if you want to affix a sidebar, wrap the sidebar code in an `AffixedSidebar` component. For instance, + +```js +class OldWay extends Component { + view() { + return
+
+
+ +
Actual Page Content
+
+
+
; + } +} + +class NewWay extends Component { + view() { + return
+
+
+ + + +
Actual Page Content
+
+
+
; + } +} +``` + +#### Fragment + +**Warning: For Advanced Use Only** + +In some rare cases, we want to have extremely fine grained control over the rendering and display of some significant chunks of the DOM. These are attached with `m.render`, and do not experience automated redraws. Current use cases in core and bundled extensions are: + +- The "Reply" button that shows up when selecting text in a post +- The mentions autocomplete menu that shows up when typing +- The emoji autocomplete menu that shows up when typing + +For this purpose, we provide a helper class (`common/Fragment`), of which you can create an instance, call methods, and render via `m.render(DOM_ROOT, fragmentInstance.render())`. The main benefit of using the helper class is that it allows you to use lifecycle methods, and to access the underlying DOM via `this.$()`, like you would be able to do with a component. + +This should only be used when absolutely necessary. If you are unsure, you probably don't need it. If the goal is to not store component instances, the "state pattern" as described above is preferable. + +### Required Frontend Changes Recap + +Each of these changes has been explained above, this is just a recap of major changes for your convenience. + +- Component Methods: + - `view()` -> `view(vnode)` + - Lifecycle + - `init()` -> `oninit(vnode)` + - `config()` -> Lifecycle hooks `oncreate(vnode)` / `onupdate(vnode)` + - `context.onunload()` -> `onremove()` + - `SubtreeRetainer` -> `onbeforeupdate()` + - if present, `attrs()` method needs to be renamed -> convention `elementAttrs()` + - building component with `MyComponent.component()` -> `children` is now second parameter instead of a named prop/attr (first argument) -> JSX preferred +- Routing + - `m.route()` -> `m.route.get()` + - `m.route(name)` -> `m.route.set(name)` + - register routes with page class, not instance + - special case when passing props + - `` -> `` +- AJAX + - `m.request({...})` -> `data:` key split up into `body:` and `params:` + - `m.deferred` -> native `Promise` +- Redrawing + - `m.redraw(true)` -> `m.redraw.sync()` + - `m.redraw.strategy('none')` -> `e.redraw = false` in event handler + - `m.lazyRedraw()` -> `m.redraw()` + +#### Deprecated changes + +For the following changes, we currently provide a backwards-compatibility layer. This will be removed in time for the stable release. The idea is to let you release a new version that's compatible with Beta 14 to your users as quickly as possible. When you have taken care of the changes above, you should be good to go. For the following changes, we have bought you time until the stable release. Considering you have to make changes anyway, why not do them now? + +- `this.props` -> `this.attrs` +- static `initProps()` -> static `initAttrs()` +- `m.prop` -> `flarum/utils/Stream` +- `m.withAttr` -> `flarum/utils/withAttr` +- `moment` -> `dayjs` + +## Backend (PHP) + +### New Features + +#### Extension Dependencies + +Some extensions are based on, or add features to, other extensions. Prior to this release, there was no way to ensure that those dependencies were enabled before the extension that builds on them. Now, you cannot enable an extension unless all of its dependencies are enabled, and you cannot disable an extension if there are other enabled extensions depending on it. + +So, how do we specify dependencies for an extension? Well, all you need to do is add them as composer dependencies to your extension's `composer.json`! For instance, if we have an extension that depends on Tags and Mentions, our `composer.json` will look like this: + +```json +{ + "name": "my/extension", + "description": "Cool New Extension", + "type": "flarum-extension", + "license": "MIT", + "require": { + "flarum/core": "^0.1.0-beta.14", + "flarum/tags": "^0.1.0-beta.14", // Will mark tags as a dependency + "flarum/mentions": "^0.1.0-beta.14", // Will mark mentions as a dependency + } + // other config +} +``` + +#### View Extender + +Previously, when extensions needed to register Laravel Blade views, they could inject a view factory in `extend.php` and call it's `addNamespace` method. For instance, + +```php +// extend.php +use Illuminate\Contracts\View\Factory; + +return [ + function (Factory $view) { + $view->addNamespace(NAME, RELATIVE PATH); + } +] +``` + +This should NOT be used, as it will break views for all extensions that boot after yours. Instead, the `View` extender should be used: + +```php +// extend.php +use Flarum\Extend\View; + +return [ + (new View)->namespace(NAME, RELATIVE PATH); +] +``` + +#### Application and Container + +Although Flarum uses multiple components of the Laravel framework, it is not a pure Laravel system. In beta 14, the `Flarum\Foundation\Application` class no longer implements `Illuminate\Contracts\Foundation\Application`, and no longer inherits `Illuminate\Container\Container`. Several things to note: + +- The `app` helper now points to an instance of `Illuminate\Container\Container`, not `Flarum\Foundation\Application`. You might need to resolve things through the container before using them: for instance, `app()->url()` will no longer work; you'll need to resolve or inject an instance of `Flarum\Foundation\Config` and use that. +- Injected or resolved instances of `Flarum\Foundation\Application` can no longer resolve things through container methods. `Illuminate\Container\Container` should be used instead. +- Not all public members of `Illuminate\Contracts\Foundation\Application` are available through `Flarum\Foundation\Application`. Please refer to our [API docs on `Flarum\Foundation\Application`](https://api.docs.flarum.org/php/master/flarum/foundation/application) for more information. + +#### Other Changes + +- We are now using Laravel 6. Please see [Laravel's upgrade guide](https://laravel.com/docs/6.x/upgrade) for more information. Please note that we do not use all of Laravel. +- Optional params in url generator now work. For instance, the url generator can now properly generate links to posts in discussions. +- A User Extender has been added, which replaces the deprecated `PrepareUserGroups` and `GetDisplayName` events. +- Error handler middleware can now be manipulated by the middleware extender through the `add`, `remove`, `replace`, etc methods, just like any other middleware. +- `Flarum/Foundation/Config` and `Flarum/Foundation/Paths` can now be injected where needed; previously their data was accessible through `Flarum/Foundation/Application`. + +### Deprecations + +- `url` provided in `config.php` is now an array, accessible via `$config->url()`, for an instance of `Config` - [PR](https://github.com/flarum/core/pull/2271#discussion_r475930358) +- AssertPermissionTrait has been deprecated - [Issue](https://github.com/flarum/core/issues/1320) +- Global path helpers and path methods of `Application` have been deprecated, the injectable `Paths` class should be used instead - [PR](https://github.com/flarum/core/pull/2155) +- `Flarum\User\Event\GetDisplayName` has been deprecated, the `displayNameDriver` method of the `User` extender should be used instead - [PR](https://github.com/flarum/core/pull/2174) + +### Removals + +- Do NOT use the old closure notation for configuring view namespaces. This will break all extensions that boot after your extension. The `View` extender MUST be used instead. +- app()->url() will no longer work: [`Flarum\Http\UrlGenerator`](routes.md) should be injected and used instead. An instance of `Flarum\Http\UrlGenerator` is available in `blade.php` templates via `$url`. +- As a part of the Laravel 6 upgrade, the [`array_` and `str_` helpers](https://laravel.com/docs/6.x/upgrade#helpers) have been removed. +- The Laravel translator interface has been removed; the Symfony translator interface should be used instead: `Symfony\Component\Translation\TranslatorInterface` +- The Mandrill mail driver is no longer provided in Laravel 6, and has been removed. +- The following events deprecated in Beta 13 [have been removed](https://github.com/flarum/core/commit/7d1ef9d89161363d1c8dea19cf8aebb30136e9e3#diff-238957b67e42d4e977398cd048c51c73): + - `AbstractConfigureRoutes` + - `ConfigureApiRoutes` - Use the `Routes` extender instead + - `ConfigureForumRoutes` - Use the `Frontend` or `Routes` extenders instead + - `ConfigureLocales` - Use the `LanguagePack` extender instead + - `ConfigureModelDates` - Use the `Model` extender instead + - `ConfigureModelDefaultAttributes` - Use the `Model` extender instead + - `GetModelRelationship` - Use the `Model` extender instead + - `Console\Event\Configuring` - Use the `Console` extender instead + - `BioChanged` - User bio has not been a core feature for several releases diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md new file mode 100644 index 000000000..3e78cd2bb --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md @@ -0,0 +1,60 @@ +# Beta 15 için Güncelleme + +Beta 15 features multiple new extenders, a total redesign of the admin dashboard, and several other interesting new features for extensions. As before, we have done our best to provide backwards compatibility layers, and we recommend switching away from deprecated systems as soon as possible to make your extensions more stable. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## New Features / Deprecations + +### Extenders + +- `Flarum\Api\Event\WillGetData` and `Flarum\Api\Event\WillSerializeData` have been deprecated, the `ApiController` extender should be used instead +- `Flarum\Api\Event\Serializing` and `Flarum\Event\GetApiRelationship` have been deprecated, the `ApiSerializer` extender should be used instead +- `Flarum\Formatter\Event\Parsing` has been deprecated, the `parse` method of the `Formatter` extender should be used instead +- `Flarum\Formatter\Event\Rendering` has been deprecated, the `render` method of the `Formatter` extender should be used instead +- `Flarum\Notification\Event\Sending` has been deprecated, the `driver` method of the `Notification` extender should be used instead + - Please note that the new notification driver system is not an exact analogue of the old `Sending` event, as it can only add new drivers, not change the functionality of the default notification bell alert driver. If your extension needs to modify **how** or **to whom** notifications are sent, you may need to replace `Flarum\Notification\NotificationSyncer` on the service provider level +- `Flarum\Event\ConfigureNotificationTypes` has been deprecated, the `type` method of the `Notification` extender should be used instead +- `Flarum\Event\ConfigurePostTypes` has been deprecated, the `type` method of the `Post` extender should be used instead +- `Flarum\Post\Event\CheckingForFlooding` has been deprecated, as well as `Flarum\Post\Floodgate`. They have been replaced with a middleware-based throttling system that applies to ALL requests to /api/*, and can be configured via the `ThrottleApi` extender. Please see our [api-throttling](api-throttling.md) documentation for more information. +- `Flarum\Event\ConfigureUserPreferences` has been deprecated, the `registerPreference` method of the `User` extender should be used instead +- `Flarum\Foundation\Event\Validating` has been deprecated, the `configure` method of the `Validator` extender should be used instead + +- The Policy system has been reworked a bit to be more intuitive. Previously, policies contained both actual policies, which determine whether a user can perform some ability, and model visibility scopers, which allowed efficient restriction of queries to only items that users have access to. See the [authorization documentation](authorization.md) for more information on how to use the new systems. Now: + - `Flarum\Event\ScopeModelVisibility` has been deprecated. New scopers can be registered via the `ModelVisibility` extender, and any `Eloquent\Builder` query can be scoped by calling the `whereVisibleTo` method on it, with the ability in question as an optional 2nd argument (defaults to `view`). + - `Flarum\Event\GetPermission` has been deprecated. Policies can be registered via the `Policy` extender. `Flarum\User\User::can` has not changed. Please note that the new policies must return one of `$this->allow()`, `$this->deny()`, `$this->forceAllow()`, `$this->forceDeny()`, not a boolean. + +- A `ModelUrl` extender has been added, allowing new slug drivers to be registered. This accompanies Flarum's new slug driving system, which allows for extensions to define custom slugging strategies for sluggable models. The extender supports sluggable models outside of Flarum core. Please see our [model slugging](slugging.md) documentation for more information. +- A `Settings` extender has been added, whose `serializeToForum` method makes it easy to serialize a setting to the forum. +- A `ServiceProvider` extender has been added. This should be used with extreme caution for advanced use cases only, where there is no alternative. Please note that the service provider layer is not considered public API, and is liable to change at any time, without notice. + +### Admin UX Redesign + +The admin dashboard has been completely redesigned, with a focus on providing navbar pages for each extension. The API for extensions to register settings, permissions, and custom pages has also been greatly simplified. You can also now update your extension's `composer.json` to provide links for funding, support, website, etc that will show up on your extension's admin page. Please see [our Admin JS documentation](admin.md) for more information on how to use the new system. + +### Other New Features + +- On the backend, the route name is now available via `$request->getAttribute('routeName')` for controllers, and for middleware that run after `Flarum\Http\Middleware\ResolveRoute.php`. +- `Flarum\Api\Controller\UploadImageController.php` can now be used as a base class for controllers that upload images (like for the logo and favicon). +- Automatic browser scroll restoration can now be disabled for individual pages [see our frontend page documentation for more info](frontend-pages.md). + +## Breaking Changes + +- The following deprecated frontend BC layers were removed: + - `momentjs` no longer works as an alias for `dayjs` + - `this.props` and `this.initProps` no longer alias `this.attrs` and `this.initAttrs` for the `Component` base class + - `m.withAttr` and `m.stream` no longer alias `flarum/utils/withAttr` and `flarum/utils/Stream` + - `app.cache.discussionList` has been removed + - `this.content` and `this.editor` have been removed from `ComposerBody` + - `this.component`, `this.content`, and `this.value` have been removed from `ComposerState` +- The following deprecated backend BC layers were removed: + - The `publicPath`, `storagePath`, and `vendorPath` methods of `Flarum\Foundation\Application` have been removed + - The `base_path`, `public_path`, and `storage_path` global helpers have been removed + - The `getEmailSubject` method of `Flarum\Notification\MailableInterface` MUST now take a translator instance as an argument + - `Flarum\User\AssertPermissionTrait` has been removed, the analogous methods on `Flarum\User\User` should be used instead + - The `Flarum\Event\PrepareUserGroups` event has been removed, use the `User` extender instead + - The `Flarum\User\Event\GetDisplayName` event has been removed, use the display name driver feature of the `User` extender instead diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md new file mode 100644 index 000000000..dbbc0cc5d --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md @@ -0,0 +1,138 @@ +# Updating For Beta 16 + +Beta 16 finalizes the PHP extender API, introduces a testing library and JS typings, switches to using namespaces for JS imports, increases extension dependency robustness, and allows overriding routes, among other features. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Frontend + +- A new editor driver abstraction has been introduced, which allows extensions to override the default textarea-based editor with more advanced solutions. +- The `TextEditor` and `TextEditorButton` components, as well as the `BasicEditorDriver` util (which replaces `SuperTextarea`) have been moved from `forum` to `common`. +- The `forum`, `admin`, and `common` namespaces should be used when importing. So instead of `import Component from 'flarum/Component'`, use `import Component from 'flarum/common/Component`. Support for the old import styles will be deprecated through the stable release, and removed with Flarum 2.0. +- A typing library has been released to support editor autocomplete for frontend development, and can be installed in your dev environment via `npm install --save-dev flarum@0.1.0-beta.16`. +- Extension categories have been simplified down to `feature`, `theme`, and `language`. + +## Backend + +### Extenders + +- All extenders that support callbacks/closures now support global functions like `'boolval'` and array-type functions like `[ClassName::class, 'methodName']`. +- The `Settings` extender's `serializeToFrontend` method now supports a default value as the 4th argument. +- The `Event` extender now supports registering subscribers for multiple events at once via a `subscribe` method. +- The `Notification` extender now has a `beforeSending` method, which allows you to adjust the list of recipients before a notification is sent. +- The `mutate` method of `ApiSerializer` has been deprecated, and renamed to `attributes`. +- `remove` methods on the `Route` and `Frontend` extenders can be used to remove (and then replace) routes. +- A `ModelPrivate` extender replaces the `GetModelIsPrivate` event, which has been deprecated. +- Methods on the `Auth` extender replace the `CheckingPassword` event, which has been deprecated. +- All search-related events are now deprecated in favor of the `SimpleFlarumSearch` and `Filter` extenders; this is explained in more detail below. + +### Laravel and Symfony + +Beta 16 upgrades from v6.x to v8.x of Laravel components and v4 to v5 of Symfony components. Please see the respective upgrade guides of each for changes you might need to make to your extensions. The most applicable change is the deprecation of `Symfony\Component\Translation\TranslatorInterface` in favor of `Symfony\Contracts\Translation\TranslatorInterface`. The former will be removed in beta 17. + +### Helper Functions + +The remaining `app` and `event` global helper functions have been deprecated. `app` has been replaced with `resolve`, which takes the name of a container binding and resolves it through the container. + +Since some Flarum extensions use Laravel libraries that assume some global helpers exist, we've recreated some commonly used helpers in the [flarum/laravel-helpers](https://github.com/flarum/laravel-helpers) package. These helpers should NOT be used directly in Flarum extension code; they are available so that Laravel-based libraries that expect them to exist don't malfunction. + +### Search Changes + +As part of our ongoing efforts to make Flarum's search system more flexible, we've made several refactors in beta 16. Most notably, filtering and searching are now treated as different mechanisms, and have separate pipelines and extenders. Essentially, if a query has a `filter[q]` query param, it will be treated as a search, and all other filter params will be ignored. Otherwise, it will be handled by the filtering system. This will eventually allow searches to be handled by alternative drivers (provided by extensions), such as ElasticSearch, without impacting filtering (e.g. loading recent discussions). Classes common to both systems have been moved to a `Query` namespace. + +Core's filtering and default search (named SimpleFlarumSearch) implementations are quite similar, as both are powered by the database. `List` API controllers call the `search` / `filter` methods on a resource-specific subclass of `Flarum\Search\AbstractSearcher` or `Flarum\Filter\AbstractFilterer`. Arguments are an instance of `Flarum\Query\QueryCriteria`, as well as sort, offset, and limit information. Both systems return an instance of `Flarum\Query\QueryResults`, which is effectively a wrapper around a collection of Eloquent models. + +The default systems are also somewhat similar in their implementation. `Filterer`s apply Filters (implementing `Flarum\Filter\FilterInterface`) based on query params in the form `filter[FILTER_KEY] = FILTER_VALUE` (or `filter[-FILTER_KEY] = FILTER_VALUE` for negated filters). SimpleFlarumSearch's `Searcher`s split the `filter[q]` param by spaces into "terms", apply Gambits (implementing `Flarum\Search\GambitInterface`) that match the terms, and then apply a "Fulltext Gambit" to search based on any "terms" that don't match an auxiliary gambit. Both systems then apply sorting, an offset, and a result count limit, and allow extensions to modify the query result via `searchMutators` or `filterMutators`. + +Extensions add gambits and search mutators and set fulltext gambits for `Searcher` classes via the `SimpleFlarumSearch` extender. They can add filters and filter mutators to `Filterer` classes via the `Filter` extender. + +With regards to upgrading, please note the following: + +- Search mutations registered by listening to the `Searching` events for discussions and users will be applied as to searches during the search mutation step via a temporary BC layer. They WILL NOT be applied to filters. This is a breaking change. These events have been deprecated. +- Search gambits registered by listening to the `ConfigureUserGambits` and `ConfigureDiscussionGambits` events will be applied to searcher via a temporary BC layer. They WILL NOT be applied to filters. This is a breaking change. These events have been deprecated. +- Post filters registered by listening to the `ConfigurePostsQuery` events will be applied to post filters via a temporary BC layer. That event has been deprecated. + +### Testing Library + +The `flarum/testing` package provides utils for PHPUnit-powered automated backend tests. See the [testing documentation](testing.md) for more info. + +### Optional Dependencies + +Beta 15 introduced "extension dependencies", which require any extensions listed in your extension's `composer.json`'s `require` section to be enabled before your extension can be enabled. + +With beta 16, you can specify "optional dependencies" by listing their composer package names as an array in your extension's `extra.flarum-extension.optional-dependencies`. Any enabled optional dependencies will be booted before your extension, but aren't required for your extension to be enabled. + +### Access Token and Authentication Changes + +#### Extension API changes + +The signature to various method related to authentication have been changed to take `$token` as parameter instead of `$userId`. Other changes are the result of the move from `$lifetime` to `$type` + +- `Flarum\Http\AccessToken::generate($userId)` no longer accepts `$lifetime` as a second parameter. Parameter has been kept for backward compatibility but has no effect. It will be removed in beta 17. +- `Flarum\Http\RememberAccessToken::generate($userId)` should be used to create remember access tokens. +- `Flarum\Http\DeveloperAccessToken::generate($userId)` should be used to create developer access tokens (don't expire). +- `Flarum\Http\SessionAccessToken::generate()` can be used as an alias to `Flarum\Http\AccessToken::generate()`. We might deprecate `AccessToken::generate()` in the future. +- `Flarum\Http\Rememberer::remember(ResponseInterface $response, AccessToken $token)`: passing an `AccessToken` has been deprecated. Pass an instance of `RememberAccessToken` instead. As a temporary compatibility layer, passing any other type of token will convert it into a remember token. In beta 17 the method signature will change to accept only `RememberAccessToken`. +- `Flarum\Http\Rememberer::rememberUser()` has been deprecated. Instead you should create/retrieve a token manually with `RememberAccessToken::generate()` and pass it to `Rememberer::remember()` +- `Flarum\Http\SessionAuthenticator::logIn(Session $session, $userId)` second parameter has been deprecated and is replaced with `$token`. Backward compatibility is kept. In beta 17, the second parameter method signature will change to `AccessToken $token`. +- `AccessToken::generate()` now saves the model to the database before returning it. +- `AccessToken::find($id)` or `::findOrFail($id)` can no longer be used to find a token, because the primary key was changed from `token` to `id`. Instead you can use `AccessToken::findValid($tokenString)` +- It's recommended to use `AccessToken::findValid($tokenString): AccessToken` or `AccessToken::whereValid(): Illuminate\Database\Eloquent\Builder` to find a token. This will automatically scope the request to only return valid tokens. On forums with low activity this increases the security since the automatic deletion of outdated tokens only happens every 50 requests on average. + +#### Symfony session changes + +If you are directly accessing or manipulating the Symfony session object, the following changes have been made: + +- `user_id` attribute is no longer used. `access_token` has been added as a replacement. It's a string that maps to the `token` column of the `access_tokens` database table. + +To retrieve the current user from inside a Flarum extension, the ideal solution which was already present in Flarum is to use `$request->getAttribute('actor')` which returns a `User` instance (which might be `Guest`) + +To retrieve the token instance from Flarum, you can use `Flarum\Http\AccessToken::findValid($tokenString)` + +To retrieve the user data from a non-Flarum application, you'll need to make an additional database request to retrieve the token. The user ID is present as `user_id` on the `access_tokens` table. + +#### Token creation changes + +The `lifetime` property of access tokens has been removed. Tokens are now either `session` tokens with 1h lifetime after last activity, or `session_remember` tokens with 5 years lifetime after last activity. + +The `remember` parameter that was previously available on the `POST /login` endpoint has been made available on `POST /api/token`. It doesn't return the remember cookie itself, but the token returned can be used as a remember cookie. + +The `lifetime` parameter of `POST /api/token` has been deprecated and will be removed in Flarum beta 17. Partial backward compatibility has been provided where a `lifetime` value longer than 3600 seconds is interpreted like `remember=1`. Values lower than 3600 seconds result in a normal non-remember token. + +New `developer` tokens that don't expire have been introduced, however they cannot be currently created through the REST API. Developers can create developer tokens from an extension using `Flarum\Http\DeveloperAccessToken::generate($userId)`. + +If you manually created tokens in the database from outside Flarum, the `type` column is now required and must contain `session`, `session_remember` or `developer`. Tokens of unrecognized type cannot be used to authenticate, but won't be deleted by the garbage collector either. In a future version extensions will be able to register custom access token types. + +#### Token usage changes + +A [security issue in Flarum](https://github.com/flarum/core/issues/2075) previously caused all tokens to never expire. This had limited security impact due to tokens being long unique characters. However custom integrations that saved a token in an external database for later use might find the tokens no longer working if they were not used recently. + +If you use short-lived access tokens for any purpose, take note of the expiration time of 1h. The expiration is based on the time of last usage, so it will remain valid as long as it continues to be used. + +Due to the large amount of expired tokens accumulated in the database and the fact most tokens weren't ever used more than once during the login process, we have made the choice to delete all access tokens a lifetime of 3600 seconds as part of the migration, All remaining tokens have been converted to `session_remember` tokens. + +#### Remember cookie + +The remember cookie still works like before, but a few changes have been made that could break unusual implementations. + +Now only access tokens created with `remember` option can be used as remember cookie. Any other type of token will be ignored. This means if you create a token with `POST /api/token` and then place it in the cookie manually, make sure you set `remember=1` when creating the token. + +#### Web session expiration + +In previous versions of Flarum, a session could be kept alive forever until the Symfony session files were deleted from disk. + +Now sessions are linked to access tokens. A token being deleted or expiring will automatically end the linked web session. + +A token linked to a web session will now be automatically deleted from the database when the user clicks logout. This prevents any stolen token from being re-used, but it could break custom integration that previously used a single access token in both a web session and something else. + +### Miscellaneous + +- The IP address is now available in requests via `$request->getAttribute('ipAddress')` +- Policies can now return `true` and `false` as aliases for `$this->allow()` and `$this->deny()`, respectively. +- The `user.edit` permission has been split into `user.editGroups`, `user.editCredentials` (for email, username, and password), and `user.edit` (for other attributes). +- There are now permissions (`bypassTagCounts`) that allow users to bypass tag count requirements. +- Flarum now supports PHP 7.3 - PHP 8.0, with support for PHP 7.2 officially dropped. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md new file mode 100644 index 000000000..184115842 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md @@ -0,0 +1,114 @@ +# Beta 8 için Güncelleme + +All extensions will need to be refactored in order to work with beta 8. Here are the main things you will need to do in order to make your extension compatible. + +:::caution + +This guide is not comprehensive. You may encounter some changes we haven't documented. If you need help, start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## PHP Namespaces + +Beta 8 comes with large changes to the overall structure of the PHP backend. You will need to look through [this list](https://discuss.flarum.org/d/6572-help-us-namespace-changes) of namespace changes and make changes to your extension accordingly. + +[This script](https://gist.github.com/tobyzerner/55e7c05c95404e5efab3a9e43799d375) can help you to automate most of the namespace changes. Of course, you should still test your extension after running the script as it may miss something. + +## Database Naming + +Many database columns and JSON:API attributes have been renamed to conform to a [convention](/contributing.md#database). You will need to update any instances where your extension interacts with core data. You can see the changes in [#1344](https://github.com/flarum/core/pull/1344/files). + +## Extenders + +Beta 8 introduces a new concept called **extenders** that replace the most common event listeners. You can learn more about how they work in the [updated extension docs](start.md#extenders). + +`bootstrap.php` has been renamed to `extend.php` and returns an array of extender instances and functions: + +```php +use Flarum\Extend; + +return [ + (new Extend\Frontend('forum')) + ->js(__DIR__.'/js/dist/forum.js') + ->css(__DIR__.'/less/forum.less') + ->route('/t/{slug}', 'tag') + ->route('/tags', 'tags'), + + function (Dispatcher $events) { + $events->subscribe(Listener\AddForumTagsRelationship::class); + } +] +``` + +If you're listening for any of the following events, you'll need to update your code to use an extender instead. See the relevant docs for more information. + +| Event | Extender | +| ------------------------------------- | --------------------------- | +| `Flarum\Event\ConfigureFormatter`* | `Flarum\Extend\Formatter` | +| `Flarum\Event\ConfigureWebApp`* | `Flarum\Extend\Frontend` | +| `Flarum\Event\ConfigureClientView`* | `Flarum\Extend\Frontend` | +| `Flarum\Event\ConfigureLocales` | `Flarum\Extend\Locales` | +| `Flarum\Event\ConfigureApiRoutes` | `Flarum\Extend\Routes` | +| `Flarum\Event\ConfigureForumRoutes` | `Flarum\Extend\Routes` | + +_\* class no longer exists_ + +## JavaScript Tooling + +Previously Flarum and its extensions used a custom Gulp workflow to compile ES6 source code into something that browsers could understand. Beta 8 switches to a more conventional approach with Webpack. + +You will need to tweak the structure of your extension's `js` directory. Currently, your JS file hierarchy looks something like the following: + +``` +js +├── admin +│ ├── src +│ │ └── main.js +│ ├── dist +│ │ └── extension.js +│ ├── Gulpfile.js +│ └── package.json +└── forum + ├── src + │ └── main.js + ├── dist + │ └── extension.js + ├── Gulpfile.js + └── package.json +``` + +You'll need to make the following changes: + +1. Update `package.json` and create `webpack.config.js`, `forum.js`, and `admin.js` files using [these templates](frontend.md#transpilation). + +2. Inside your `admin` and `forum` *folders*, delete `Gulpfile.js`, `package.json`, and `dist`. Then inside each `src` folder, rename `main.js` to `index.js`. Now move all of the `src` files outside of `src` folder and delete it. + +3. In the root `js` folder create a folder called `src` and move your `admin` and `forum` *folders* into it. + +4. While still in your root `js` folder, run `npm install` and then `npm run build` to build the new JS dist files. + +If everything went right, your folder structure should look something like this: + +``` +js +├── src +│ ├── admin +│ │ └── index.js +│ └── forum +│ └── index.js +├── dist +│ ├── admin.js +│ ├── admin.js.map +│ ├── forum.js +│ └── forum.js.map +├── admin.js +├── forum.js +├── package.json +└── webpack.config.js +``` + +Take a look at the [bundled extensions](https://github.com/flarum) for more examples. + +## Font Awesome Icons + +Beta 8 upgrades to Font Awesome 5, in which icon class names have changed. The `flarum/helpers/icon` helper now requires the **full Font Awesome icon class names** to be passed, eg. `fas fa-bolt`. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/views.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/views.md new file mode 100644 index 000000000..fc4a75a86 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extend/views.md @@ -0,0 +1,63 @@ +# Views and Blade + +Although the Flarum UI you know and love is powered by our [Mithril frontend](frontend), server-side generated templates are still used throughout Flarum. Most notably, the HTML skeleton of the forum, which includes various SEO meta tags, as well as the no-js view of the forum, is implemented through the Views and Blade systems. + +[Blade](https://laravel.com/docs/8.x/blade) is Laravel's templating engine, which allows you to conveniently generate HTML (or other static content) from PHP. It's the same idea as [Jinja](https://jinja.palletsprojects.com/en/3.0.x/) or [EJS](https://ejs.co/). [Views](https://laravel.com/docs/8.x/views) are Laravel's system for organizing/registering Blade templates, and also includes utilities for rendering them and providing them with variables. + +For our purposes, views are directories containing `.blade.php` template files (possibly contained in subdirectories). + +## Adding Views + +You will need to tell the view factory where it can find your extension's view files by adding a `View` extender to `extend.php`: + +```php +use Flarum\Extend; +use Illuminate\Contracts\View\Factory; + +return [ + (new Extend\View) + ->namespace('acme.hello-world', __DIR__.'/views'), +]; +``` + + +## Blade Templates + +To learn about the syntax for Blade templates, read [Laravel's documentation](https://laravel.com/docs/8.x/blade). + +Once you've set up your views, you can render them to strings: + +```php +// Here, $view is of type `Illuminate\Contracts\View\Factory` +$renderedString = $view->make('acme.hello-world::greeting')->render(); + +// You can also pass variables to the view: +$renderedString = $view->make('acme.hello-world::greeting', ['varName' => true])->render(); +``` + +You can obtain the view factory instance through dependency injection. + +The format is `"VIEW_NAMESPACE::VIEW_NAME"`. If the view folder is organized as subdirectories, replace `/` with `.` in the pack. So if you have a file at `"forum/error.blade.php"` in a namespace called `"custom-views"`, you would use `"custom-views::forum.error"`. + +Note that all Blade templates rendered this way automatically have access to the following variables: + +- `$url`: a [URL generator](routes#generating-urls) instance. +- `$translator`: a [Translator](i18n#server-side-translation) instance. +- `$settings`: a [SettingsInterface](settings) instance. +- `$slugManager`: a [SlugManager](slugging) instance. + +Additionally, templates used by [content logic](routes#content) have access to `$forum`, which represents the [Forum API Document's attributes](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Serializer/ForumSerializer.php#L19). + +## Overriding Views + +If you want to override templates added by core or extensions, set up a view folder structure matching the one you are trying to override, containing just the files you are trying to override. Then use the `View` extender's `extendNamespace` method: + +```php +use Flarum\Extend; +use Illuminate\Contracts\View\Factory; + +return [ + (new Extend\View) + ->extendNamespace('acme.hello-world', __DIR__.'/override_views'); +]; +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extenders.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extenders.md new file mode 100644 index 000000000..0731aa756 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extenders.md @@ -0,0 +1,23 @@ +# Yerel Genişleticiler + +If there are customizations you want to make to your site without distributing an entire extension, you can do so by using **local extenders**. Each Flarum installation comes with an `extend.php` file where you can add extender instances, just like in a full extension. + +See our [extension documentation](extend/start.md) for more information about extenders (and even an [example of a local extender](extend/start.md#hello-world)). + +If you need to create new files (when adding a custom class to be imported for extenders), you'll need to adjust your composer.json a bit. Add the following: + +```json +"autoload": { + "psr-4": { + "App\\": "app/" + } +}, +``` + +Now you can create new PHP files in an `app` subdirectory using the `App\...` namespace. + +:::tip Local Extenders vs Extensions + +Local extenders can be good for small tweaks, but if you need large customizations, an extension might be a better choice: a separate codebase, cleaner handling of many files, developer tooling, and the ability to easily open source are big benefits. + +::: diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extensions.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extensions.md new file mode 100644 index 000000000..9e6adb27c --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/extensions.md @@ -0,0 +1,118 @@ +# Uzantılar + +Flarum minimalisttir, ancak aynı zamanda oldukça genişletilebilir. Aslında, Flarum ile birlikte gelen özelliklerin çoğu aslında uzantılardır! + +Bu yaklaşım Flarum'u son derece özelleştirilebilir kılar: İhtiyaç duymadığınız tüm özellikleri devre dışı bırakabilir ve forumunuzu topluluğunuz için mükemmel hale getirmek için diğer uzantıları yükleyebilirsiniz. + +Flarum'un temelde hangi özellikleri dahil ettiğimiz konusundaki felsefesi hakkında daha fazla bilgi için veya kendi uzantınızı oluşturmak istiyorsanız, lütfen [uzantı belgelerimize](extend/README.md) bakın. Bu makale, bir forum yöneticisinin bakış açısından uzantıları yönetmeye odaklanacaktır. + +## Uzantı Yöneticisi + +Uzantı yöneticisi, bir arşiv aracılığıyla yüklendiğinde Flarum ile birlikte gelen bir uzantıdır. Hem uzantıları hem de Flarum'u yüklemek ve güncellemek için grafiksel bir arayüz sağlar. + +Eğer eklenti yöneticiniz kurulu değilse ve onu kurmak istiyorsanız Flarum dizininizde aşağıdaki komutu çalıştırarak bunu yapabilirsiniz: + +```bash +composer require flarum/extension-manager:"*" +``` + +:::warning + +Uzantı yöneticisi, yönetici kullanıcının herhangi bir besteci paketini yüklemesine olanak tanır. Uzantı yöneticisini yalnızca bu tür izinlere sahip tüm forum yöneticilerinize güveniyorsanız yükleyin. + +::: + +![uzantı yöneticisi yönetici sayfası](https://github.com/flarum/docs/assets/20267363/d0e1f7a5-e194-4acd-af63-7b8ddd95c26b) + + +## Uzantıları Bulmak + +Flarum, çoğu açık kaynaklı ve ücretsiz olan geniş bir uzantı ekosistemine sahiptir. Yeni ve harika uzantılar bulmak için, Flarum'un topluluk forumundaki [Extensions](https://discuss.flarum.org/t/extensions) etiketini ziyaret edin. Resmi olmayan [Extiverse](https://extiverse.com/) de harika bir kaynaktır. + +## Uzantıları Yükleme + +### Arayüz aracılığıyla + +Uzantı yöneticisi uzantısını kullanarak uzantıları doğrudan yönetici kontrol panelinden yükleyebilirsiniz. Yukarıdaki bağlantılardan mevcut uzantıların listesine göz attığınızda ve yüklemek istediğiniz uzantıyı bulduğunuzda, uzantı yöneticisinin kurulum girişine uzantının besteci paketi adını girerek yükleyebilirsiniz. + +![Installing an extension](/en/img/install-extension.png) + +### Komut satırı aracılığıyla + +Flarum gibi, uzantılar da SSH kullanılarak [Composer](https://getcomposer.org) aracılığıyla yüklenir. Tipik bir uzantı yüklemek için: + +1. `cd` to your Flarum directory. Bu dizin `composer.json`, `flarum` dosyalarını ve bir `storage` dizini (diğerlerinin yanı sıra) içermelidir. Dizin içeriğini `ls -la` aracılığıyla kontrol edebilirsiniz. +2. Çalıştırın `composer require COMPOSER_UZANTI_ADI:*`. Bu, uzantının belgelerinde sağlanmalıdır. + +## Uzantıları Yönetme + +### Arayüz aracılığıyla + +Uzantı yöneticisi uzantısını kullanarak uzantıları doğrudan yönetici kontrol panelinden güncelleyebilirsiniz. Uzantı yöneticisindeki "Güncellemeleri kontrol et" düğmesini tıklayarak güncellemeleri kontrol edebilirsiniz. Güncellemeler mevcutsa, "Global güncelleme" butonuna tıklayarak tüm uzantıları güncelleyebilirsiniz. Veya güncellemek istediğiniz uzantının yanındaki "Güncelle" butonuna tıklayarak uzantıları tek tek güncelleyebilirsiniz. + +![Updating an extension](/en/img/update-extension.png) + +### Komut satırı aracılığıyla + +Uzantı geliştiricileri tarafından sağlanan talimatları izleyin. Uzantılar için sürüm dizesi olarak `*` kullanıyorsanız ([önerildiği gibi](composer.md)), [Flarum yükseltme kılavuzunda](update.md) listelenen komutları çalıştırmak güncellenecektir tüm uzantılarınız. + +## Uzantıları Kaldırma + +### Arayüz aracılığıyla + +Uzantı yöneticisi uzantısını kullanarak uzantıları doğrudan yönetici kontrol panelinden yükleyebilirsiniz. Uzantının sayfasında, kaldırmak istediğiniz uzantının yanındaki "Kaldır" düğmesini tıklayarak bir uzantıyı kaldırabilirsiniz. + +![Uninstalling an extension](/en/img/uninstall-extension.png) + +### Komut satırı aracılığıyla + +Kuruluma benzer şekilde bir uzantıyı kaldırmak için: + +0. Uzantı tarafından oluşturulan tüm veritabanı tablolarını kaldırmak istiyorsanız yönetici kontrol panelindeki "Temizle" düğmesini tıklayın. Daha fazla bilgi için [aşağıya](#managing-extensions) bakın. +1. `cd` to your Flarum directory. +2. Çalıştırın `composer require COMPOSER_UZANTI_ADI:*`. Bu, uzantının belgelerinde sağlanmalıdır. + +## Uzantıları Yönetme + +Yönetici kontrol panelindeki her bir uzantı sayfası, uzantıyı yönetmek için kullanışlı bir yol sağla. Yapabilecekleriniz: + +- Uzantıyı etkinleştirin veya devre dışı bırakın. +- Uzantının sağladığı ayarlara bakın ve bunları değiştirin. +- Bir uzantının yaptığı tüm veritabanı değişikliklerini kaldırmak için, uzantının geçişlerini geri alın (bu, Temizle düğmesiyle yapılabilir). Bu, uzantı ile ilişkili TÜM verileri kaldırır ve geri alınamaz. Bu yalnızca bir uzantıyı kaldırırken yapılmalıdır ve tekrar yüklemeyi planlamayın. Aynı zamanda tamamen isteğe bağlıdır. +- Varsa, uzantının README dosyasına bakın. +- Uzantının sürümüne bakın. +- Uzantı yöneticisi yüklüyse uzantıyı kaldırın. + +## Configuring additional extension repository sources + +The extension manager uses `composer` under the hood, and as such, it looks for extension packages in the same places as `composer`. By default, this is [Packagist](https://packagist.org/). However, you can configure additional sources for the extension manager to look for extensions in. This is useful if you want to install an extension that is not available on Packagist. + +In the admin page of the extension manager, clicking the **Add Repository** button will open a modal where you can enter the name and URL of the repository you want to add. The name is just a label for the repository, and can be anything you want. The URL should be the URL of the repository which depends on the type of repository you want to add. + +### Adding a repository from a VCS + +If you want to add a repository from a VCS (e.g. GitHub, GitLab, BitBucket, etc), the URL should be the URL of the repository's VCS. For example, if you had a private GitHub repository at `https://github.com/acme/flarum-extension`, you would enter that URL into the URL field. If it is a private source, you will need to enter an authentication method through the **New authentication method** button. The token can be generated from your VCS provider's website, and the host should be the domain of the VCS provider (e.g. `github.com`). + +### Adding a composer repository + +Extiverse provides access to premium extensions. It is a good example of a composer repository. You would specify the URL as `https://flarum.org/composer/` and the name as `premium`. You would also need to enter an authentication method through the **New authentication method** button. The token can be generated from your Flarum account's [subscriptions](https://flarum.org/dashboard/subscriptions) page with the Instructions button. + +* Type: `HTTP Bearer` +* Host: `flarum.org` + +![Configure repositories](/en/img/config-repositories.png) + +:::bilgi + +The configured repositories and auth methods will be active for both the command line and the admin dashboard. If you configure them from the command line however, you must not include the flag `--global`. + +::: + +## Installing Non-stable extensions + +If for whatever reason you want to install a non-stable extension (e.g. a beta, alpha or RC version) you must first update the **Minimum stability** setting to the wanted stability. + +* If you set it to Alpha, you will be able to install alpha, beta, RC (Release Candidate) and stable versions. +* If you set it to Beta, you will be able to install beta, RC and stable versions. +* If you set it to RC, you will be able to install RC and stable versions. +* If you set it to Stable, you will only be able to install stable versions. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/faq.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/faq.md new file mode 100644 index 000000000..ceceb4948 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/faq.md @@ -0,0 +1,35 @@ +# SSS + +### Flarum ne zaman kararlı olacak? + +Yes! After 6 years of development, Flarum 1.0.0 is finally here. + +### Beta'dan sonraki sürümlere geçiş yapabilecek miyim? + +We're still working on a formal roadmap. We have a lot of plans and ideas, and look forward to sharing a more thorough milestone with the community. + +### Geliştirmeyi hızlandırmak için para bağışlayabilir miyim? + +Tüm bağışlar minnetle alındı. [Github Sponsors](https://github.com/sponsors/flarum) veya [OpenCollective](https://opencollective.com/flarum) üzerinden verebilirsiniz. + +Ancak bağışlar, Flarum'daki geliştirme hızını doğrudan etkilemeyecek. Ayrıca, kullanıcıları [katkıda bulunan kod](contributing.md), [uzantıları oluşturma](/extend/), belge yazma, Flarum'u diğer dillere çevirme, [topluluk forumlarında](https://discuss.flarum.org/) yardım ve destek sağlama gibi başka şekillerde katkıda bulunmaya teşvik ediyoruz. ...ve sadece topluluk etrafında genel bir pozitif enerji olmak! + +### Flarum'da [özelliği buraya ekleyin] olacak mı? Ne zaman? Neden olmasın? + +Flarum için sayısız özellik ve uzantı oluşturmayı çok isteriz, ancak her şeyden önce: Odak noktamız temeller ve kararlılıktır. + +### Why haven’t you fixed [insert issue here] yet? + +Burada yine cevap “ilk önce şeyler”dir. Henüz bir sorunu çözmediysek (veya ona bir kilometre taşı atamadıysak), bunun nedeni aynı derecede önemli olan başka bir şey üzerinde çalıştığımızdır. Lütfen sabırlı olun; yayınlanmadan önce halletmeye çalışacağız. Veya aceleniz varsa, bunu kendiniz düzeltmekten çekinmeyin ve [projeye katkıda bulunun](Contributing.md)! + +### Forumumu Flarum'a taşıyabilecek miyim? + +We don't currently provide official migrators, but there are many community solutions out there. Flarum'un üretimde kullanılmaya hazır olduğundan emin olduktan sonra, esoTalk, FluxBB, phpBB, Discourse ve diğerleri gibi diğer forum yazılımlarından verileri içeri aktarmak için araçlar oluşturmaya başlayacağız. + +### Neden henüz [sorunu buraya ekleyin] sorunu çözmediniz? + +> "Mistik ritüeller, yaşamı tehdit eden tehlikeler ve birçoğunun gittiği ve çok azının geri döndüğü uzak diyarlara maceralar içeren gizemli ve zorlu bir çileden geçerek." ~ jordanjay29 + +Gerçek cevap, genel olarak topluluğumuza iyi personel olacak öne çıkan üyeler için göz kulak olmamızdır. Açıkçası, mevcut çalışanlarımızın çoğu için, personel olmadan önce yaptıkları, şu anda yaptıklarından çok da farklı değildi. + +Bir tutku bulun ve en iyi olduğunu düşündüğünüz şekilde katkıda bulunun. O zaman kendi yoluna gitmesine izin verin. Burada saygı duymak için bir rozete sahip olmanız gerekmiyor. \ No newline at end of file diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/install.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/install.md new file mode 100644 index 000000000..ca61cd0c4 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/install.md @@ -0,0 +1,198 @@ +# Kurulum + +:::ipucu Hızlı test sürüşü mü? + +Flarum'u [gösteri forumlarımızdan](https://discuss.flarum.org/d/21101) birinde denemekten çekinmeyin. Veya Flarum ekibine bağlı olmayan ücretsiz bir topluluk hizmeti olan [Free Flarum](https://www.freeflarum.com)'da kendi forumunuzu birkaç saniye içinde kurun. + +::: + +## Sunucu Gereksinimleri + +Flarum'u kurmadan önce, sunucunuzun gereksinimleri karşılayıp karşılamadığını kontrol etmeniz önemlidir. Flarum'u çalıştırmak için şunlara ihtiyacınız olacak: + +* **Apache** (mod_rewrite etkin) veya **Nginx** +* **PHP 7.3+** şu uzantılara sahip: curl, dom, fileinfo, gd, json, mbstring, openssl, pdo\_mysql, tokenizer, zip +* **MySQL 5.6+/8.0.23+** veya **MariaDB10.0.5+** Composer'ı çalıştırmak için **SSH (komut satırı) erişimi** +* **SSH (command-line) access** to run potentially necessary software maintenance commands, and Composer if you intend on using the command-line to install and manage Flarum extensions. + +## Yükleme + +### Installing by unpacking an archive + +If you don't have SSH access to your server or you prefer not to use the command line, you can install Flarum by unpacking an archive. Below is a list of the available archives, make sure you choose the one that matches your PHP version and public path or lack thereof preference. + +| Flarum Version | PHP Version | Public Path | Type | Archive | +| -------------- | ----------------- | ----------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1.x | 8.3 (recommended) | No | ZIP | [flarum-v1.x-no-public-dir-php8.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.3.zip) | +| 1.x | 8.3 (recommended) | Yes | TAR.GZ | [flarum-v1.x-php8.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.3.tar.gz) | +| 1.x | 8.3 (recommended) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.3.tar.gz) | +| 1.x | 8.3 (recommended) | Yes | ZIP | [flarum-v1.x-php8.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.3.zip) | +| 1.x | 8.2 (recommended) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.2.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.2.tar.gz) | +| 1.x | 8.2 (recommended) | Yes | TAR.GZ | [flarum-v1.x-php8.2.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.2.tar.gz) | +| 1.x | 8.2 (recommended) | No | ZIP | [flarum-v1.x-no-public-dir-php8.2.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.2.zip) | +| 1.x | 8.2 (recommended) | Yes | ZIP | [flarum-v1.x-php8.2.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.2.zip) | +| 1.x | 8.1 | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.1.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.1.tar.gz) | +| 1.x | 8.1 | Yes | TAR.GZ | [flarum-v1.x-php8.1.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.1.tar.gz) | +| 1.x | 8.1 | No | ZIP | [flarum-v1.x-no-public-dir-php8.1.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.1.zip) | +| 1.x | 8.1 | Yes | ZIP | [flarum-v1.x-php8.1.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.1.zip) | +| 1.x | 8.0 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.0.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.0.tar.gz) | +| 1.x | 8.0 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php8.0.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.0.tar.gz) | +| 1.x | 8.0 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php8.0.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.0.zip) | +| 1.x | 8.0 (end of life) | Yes | ZIP | [flarum-v1.x-php8.0.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.0.zip) | +| 1.x | 7.4 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php7.4.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.4.tar.gz) | +| 1.x | 7.4 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php7.4.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.4.tar.gz) | +| 1.x | 7.4 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php7.4.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.4.zip) | +| 1.x | 7.4 (end of life) | Yes | ZIP | [flarum-v1.x-php7.4.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.4.zip) | +| 1.x | 7.3 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php7.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.3.tar.gz) | +| 1.x | 7.3 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php7.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.3.tar.gz) | +| 1.x | 7.3 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php7.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.3.zip) | +| 1.x | 7.3 (end of life) | Yes | ZIP | [flarum-v1.x-php7.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.3.zip) | + +### Installing using the Command Line Interface + +Flarum, bağımlılıklarını ve uzantılarını yönetmek için [Composer](https://getcomposer.org) kullanır. Flarum'u kurmadan önce, makinenize [Composer'ı kurmanız](https://getcomposer.org) gerekir. Daha sonra, bu komutu Flarum'un yüklenmesini istediğiniz boş bir konumda çalıştırın: + +```bash +composer create-project flarum/flarum . +``` + +Bu komut çalışırken web sunucunuzu yapılandırabilirsiniz. Root klasörünüzü `/path/to/your/forum/public` olarak ayarlandığından emin olmanız ve aşağıdaki talimatlara göre \[URL Yeniden Yazma\] (# url-yeniden yazma) ayarlamanız gerekir. + +Her şey hazır olduğunda, bir web tarayıcısında forumunuza gidin ve kurulumu tamamlamak için talimatları izleyin. + +If you wish to install and update extensions from the admin dashboard, you need to also install the [Extension Manager](extensions.md) extension. + +```bash +composer require flarum/extension-manager:* +``` + +:::warning + +Uzantı yöneticisi, yönetici kullanıcının herhangi bir besteci paketini yüklemesine olanak tanır. Uzantı yöneticisini yalnızca bu tür izinlere sahip tüm forum yöneticilerinize güveniyorsanız yükleyin. + +::: + +## URL Yönlendirme + +### Apache + +Flarum, `public` dizininde bir `.htaccess` dosyası içerir - doğru şekilde yüklendiğinden emin olun. **`mod_rewrite` etkin değilse veya `.htaccess` e izin verilmiyorsa Flarum düzgün çalışmayacaktır.** Bu özelliklerin etkin olup olmadığını barındırma sağlayıcınıza danışın. Kendi sunucunuzu yönetiyorsanız, `.htaccess` dosyalarını etkinleştirmek için site yapılandırmanıza aşağıdakileri eklemeniz gerekebilir: + +``` + + AllowOverride All + +``` + +Bu, htaccess geçersiz kılmalarına izin verilmesini sağlar, böylece Flarum URL'leri düzgün şekilde yeniden yazabilir. + +`mod_rewrite` ı etkinleştirme yöntemleri işletim sisteminize bağlı olarak değişir. Ubuntu'da `sudo a2enmod rewrite` çalıştırarak etkinleştirebilirsiniz. CentOS'ta `mod_rewrite` varsayılan olarak etkindir. Değişiklikler yaptıktan sonra Apache'yi yeniden başlatmayı unutmayın! + +### Nginx + +Flarum bir `.nginx.conf` dosyası içerir - doğru şekilde yüklendiğinden emin olun. Ardından, Nginx içinde kurulmuş bir PHP siteniz olduğunu varsayarak, sunucunuzun yapılandırma bloğuna aşağıdakileri ekleyin: + +```nginx +include /path/to/flarum/.nginx.conf; +``` + +### Caddy + +Caddy, Flarum'un düzgün çalışması için çok basit bir konfigürasyon gerektirir. URL'yi kendi URL'niz ile ve dizinide de kendi `public` klasörünüzün dizini ile değiştirmeniz gerektiğini unutmayın. PHP'nin farklı bir sürümünü kullanıyorsanız, doğru PHP yükleme soketinize veya URL'nize işaret etmek için `fastcgi` dizinini de değiştirmeniz gerekecektir. + +``` +www.example.com { + root * /var/www/flarum/public + php_fastcgi unix//var/run/php/php7.4-fpm.sock + header /assets/* { + +Cache-Control "public, must-revalidate, proxy-revalidate" + +Cache-Control "max-age=25000" + Pragma "public" + } + file_server +} +``` +## Klasör Sahipliği + +Kurulum sırasında Flarum, belirli dizinleri yazılabilir hale getirmenizi isteyebilir. Modern işletim sistemleri genellikle çok kullanıcılıdır, yani oturum açtığınız kullanıcı ile Flarum'un çalıştığı kullanıcı aynı değildir. Flarum'un çalıştığı kullanıcı, aşağıdakiler için okuma + yazma erişimine sahip olmalıdır: + +- Flarum'un `config.php` dosyasını düzenleyebilmesi için kök kurulum dizini. +- `storage` alt dizini, böylece Flarum günlükleri düzenleyebilir ve önbelleğe alınmış verileri saklayabilir. +- Logoların ve avatarların dosya sistemine yüklenebilmesi için `assets` alt dizini. + +Uzantılar başka dizinler gerektirebilir, bu nedenle Flarum kök kurulum dizininin tamamına tekrar tekrar yazma erişimi vermek isteyebilirsiniz. + +Dosya izinlerini ayarlamak için çalıştırmanız gereken birkaç komut vardır. Yüklemeniz bunlardan yalnızca bazılarını yürüttükten sonra uyarı göstermiyorsa geri kalanını çalıştırmanıza gerek olmadığını lütfen unutmayın. + +Öncelikle, dizine yazma erişimine izin vermeniz gerekir. Linux'ta: + +```bash +chmod 775 -R /path/to/directory +``` + +Bu yeterli değilse, dosyalarınızın doğru grup ve kullanıcıya ait olup olmadığını kontrol etmeniz gerekebilir. Varsayılan olarak, çoğu Linux dağıtımında `www-data` hem PHP'nin hem de web sunucusunun altında çalıştığı grup ve kullanıcıdır. Emin olmak için dağıtım ve web sunucusu kurulumunuzun özelliklerini incelemeniz gerekir. Çoğu Linux işletim sisteminde klasör sahipliğini aşağıdakileri çalıştırarak değiştirebilirsiniz: + +```bash +chown -R www-data:www-data /path/to/directory +``` + +Web sunucunuz için farklı bir kullanıcı/grup kullanılıyorsa, `www-data` başka bir şeye değiştirildi. + +Ek olarak, uzantıları kurabilmeniz ve CLI aracılığıyla Flarum kurulumunu yönetebilmeniz için CLI kullanıcınızın (terminalde oturum açtığınız kişi) sahip olduğundan emin olmanız gerekir. Bunu yapmak için mevcut kullanıcınızı (`whoami`) `usermod -a -G www-data YOUR_USERNAME` aracılığıyla web sunucusu grubuna (genellikle `www-data`) ekleyin. Bu değişikliğin etkili olması için muhtemelen oturumu kapatıp tekrar açmanız gerekecek. + +Son olarak, bu işe yaramazsa, web sunucusunun dizine yazmasına izin vermek için [SELinux](https://www.redhat.com/en/topics/linux/what-is-selinux)'u yapılandırmanız gerekebilir. Bunu yapmak için şunu çalıştırın: + +```bash +chcon -R -t httpd_sys_rw_content_t /path/to/directory +``` + +Bu komutların yanı sıra Linux'ta dosya izinleri ve sahiplik hakkında daha fazla bilgi edinmek için [bu öğreticiyi](https://www.thegeekdiary.com/understanding-basic-file-permissions-and-ownership-in-linux/) okuyun. Flarum'u Windows'ta kuruyorsanız, [bu Süper Kullanıcı sorusunun](https://superuser.com/questions/106181/equivalent-of-chmod-to-change-file-permissions-in-windows) yanıtlarını faydalı bulabilirsiniz. + +:::caution Ortamlar değişebilir + +Ortamınız sağlanan belgelerden farklı olabilir, lütfen PHP ve web sunucusunun altında çalıştığı uygun kullanıcı ve grup için web sunucusu yapılandırmanıza veya web barındırma sağlayıcınıza danışın. + +::: + +:::danger 777 iznini asla kullanmayın + +Herhangi bir klasör veya dosyayı asla `777` izin düzeyine ayarlamamalısınız. Çünkü bu izin düzeyi, kullanıcı veya gruptan bağımsız olarak herkesin klasör ve dosyanın içeriğine erişmesine izin verir. + +::: + +## Dizinleri Özelleştirme + +Varsayılan olarak Flarum'un dizin yapısı, yalnızca herkesin erişebileceği dosyaları içeren bir `public` dizini içerir. Bu, tüm hassas kaynak kodu dosyalarına web kökünden tamamen erişilemez olmasını sağlayan en iyi güvenlik uygulamasıdır. + +Ancak, Flarum'u bir alt dizinde (`domain.tld/forum` gibi) barındırmak istiyorsanız veya barındırıcınız size web kökünüz üzerinde kontrol sağlamıyorsa (gibi bir şeye takılıp kalırsınız) `public_html` veya `htdocs`, Flarum'u `public` dizini olmadan kurabilirsiniz. + +If you intend to install Flarum using one of the archives, you can simply use the `no-public-dir` (Public Path = No) [archives](#installing-by-unpacking-an-archive) and skip the rest of this section. If you're installing via Composer, you'll need to follow the instructions below. + +`public` dizini içindeki tüm dosyaları (`.htaccess` dahil) Flarum'a hizmet vermek istediğiniz dizine taşımanız yeterlidir. Ardından, hassas kaynakları korumak için `.htaccess` dosyasını düzenleyin ve 9-15 satırlarındaki açıklamaları kaldırın. Nginx için, `.nginx.conf`'un 8-11. satırlarındaki yorumları kaldırın. + +Ayrıca `index.php` dosyasını düzenlemeniz ve aşağıdaki satırı değiştirmeniz gerekecektir: + +```php +$site = require './site.php'; +``` + + `site.php` dosyasını düzenleyin ve aşağıdaki satırlardaki yolları yeni dizin yapınızı yansıtacak şekilde güncelleyin: + +```php +'base' => __DIR__, +'public' => __DIR__, +'storage' => __DIR__.'/storage', +``` + +Son olarak, `config.php`'yi kontrol edin ve `url` değerinin doğru olduğundan emin olun. + +## Verileri İçe Aktarma + +Mevcut bir topluluğunuz varsa ve sıfırdan başlamak istemiyorsanız, mevcut verilerinizi Flarum'a aktarabilirsiniz. Henüz resmi bir ithalatçı olmasa da, topluluk birkaç resmi olmayan ithalatçı yaptı: + +* [FluxBB](https://discuss.flarum.org/d/3867-fluxbb-to-flarum-migration-tool) +* [MyBB](https://discuss.flarum.org/d/5506-mybb-migrate-script) +* [phpBB](https://discuss.flarum.org/d/1117-phpbb-migrate-script-updated-for-beta-5) +* [SMF2](https://github.com/ItalianSpaceAstronauticsAssociation/smf2_to_flarum) + +Bunlar, önce phpBB'ye, ardından Flarum'a geçirilerek diğer forum yazılımları için de kullanılabilir. Bunların çalışacağını garanti edemeyeceğimizi ve onlar için destek sağlayamayacağımızı unutmayın. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/README.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/README.md new file mode 100644 index 000000000..ce923579d --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/README.md @@ -0,0 +1,7 @@ +--- +slug: '/internal' +--- + +# Internal Team Docs + +Bu, Flarum ekibi tarafından dahili olarak kullanılan bazı belgeleri yayınlayacağımız yeni bir belgeleme bölümüdür. We are starting this section to provide our community with transparency as to how Flarum is run, and to help those hoping to contribute to Flarum. \ No newline at end of file diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md new file mode 100644 index 000000000..555e7977c --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md @@ -0,0 +1,28 @@ +# Bundled Extensions Policy + +This document is to assist in deciding what core features should be bundled or maintained by the Flarum project team. + +Understand that Flarum aims to have a lean and efficient team. To guarantee a transparent workload, we intentionally have a "this could be an extension" mentality. The acronym D.O.R.C. spells out our decision-making process. + +- **Density**: prevent bloating Flarum so that it becomes a burden to install on shared hosting plans with limited space. +- **Opinionatedness**: no extensions should be bundled that is only useful by only a limited amount of communities or on specific hosting environments. +- **Responsibility**: extensions that could easily be maintained by others should be maintained by others. +- **Complexity**: extensions that are complex in terms of design, frontend or backend code should not be a responsibility of the Flarum project team. + +### Density + +To prevent the installation size of Flarum from continuously increasing we need to protect it from extensions that bloat it. We should ship extensions with Flarum that, for instance, have kilobytes in media files. + +### Opinionatedness + +Our goal is to allow installation of Flarum, in its vanilla form, by any community on any hosting environment. This includes shared hosting environment as well. + +Releasing Flarum with extensions that add functionality specific to cloud based (AWS) installations or for corporate support communities, as such, is unwanted. + +### Responsibility + +Protecting the time of the project team is key. To do so we should empower the ecosystem in building extensions that it needs. Therefor we distance ourselves from the responsibility of building every and all extensions. The responsibility of extension development is held primarily by our community. + +### Complexity + +Complex extensions require a vast amount of time, not just for development, but also documentation and support. To protect the lean and efficient principles of the team, we will not take ownership of extensions that add this complexity. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md new file mode 100644 index 000000000..e448a6601 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md @@ -0,0 +1,87 @@ +# Uzantı Yöneticisi +This contains an explanation of how the extension manager works and what it has to offer. + +slightly outdated: see [the extensions guide for more](/extensions.md). + +## Contents +* Installing, Updating, and Removing Extensions. +* [Checking for Updates](#checking-for-updates). +* [Global Flarum Update](#global-flarum-updates). +* [Patch-Minor Flarum Updates](#patch-minor-flarum-updates). +* [Major Flarum Update](#major-flarum-updates). +* [Flarum Updates (global, minor, major)](#flarum-updates-global-minor-major). +* [Background Tasks](#background-tasks). + +## Requirements +There are some obstacles that need to be taken care of before this can be used. + +### File Permissions +The relevant machine web user needs to have permissions to read and write to: `vendor`, `composer.json`, `composer.lock` and `storage`. Right now a warning shows up when this is not the case, this should preferably be changed to mention only the files/dirs where permissions are lacking instead of all of them. + +![flarum lan_admin (3)](https://user-images.githubusercontent.com/20267363/135268536-f79d42ab-6e05-4e41-b2ab-d95ec7a8b021.png) + +### Path Repository +In development environments (and production in rare scenarios) there should a path repository to a directory containing (mostly dev) packages, the path to this directory must be changed to an absolute path otherwise composer will have trouble running any command. Additionally the path repository by default has higher priority, so requiring an extension that exists in that repository will probably fail, unless a `*@dev` constraint is specified, in which case the extension manager should not be used for dev purposes anyway. + +There is currently now hint of any of this in the extension manager UI. + +## Common Actions +Each one of the features listed above is basically a composer command or two, and there are common actions/common behaviour between them all. + +* Restricting access to the admin. +* Validating the provided package name or the extension id if given. +* Erroring out if installing an existing extension, updating or removing a non existing extension ...etc +* Running the command. This [auto logs the output](#command-output-logging). +* [Erroring out on command failure](#command-failure). +* Dispatching an event. +* If running an update: + + Clear Cache. + + Run Migrations. + + Publish Assets. + + Run an update check, and log any extensions that didn't update to their latest versions in the update process. + +### Command Output Logging +Considering this is still experimental and especially for the sake of easier support, each command output is logged to `storage/logs/composer` just like the flarum error logs, allowing to go back and see what happened during a command execution. + +### Command Failure +When a composer command fails (recognised by the exit code), an exception is thrown containing a reason guessed by the exception based on the command output text. Guessed causes render into proper explanatory alert messages on the frontend. + +## Checking for Updates +This executes the command `composer outdated -D --format json` which checks for updates of packages directly required in the root `composer.json` and outputs the results in JSON format. Only packages marked as `semver-safe-update` and `update-possible` by composer are displayed. + +The information about the last update check is saved into a JSON setting. + +![flarum lan_admin (4)](https://user-images.githubusercontent.com/20267363/135272032-9de37599-b364-4e42-b234-1113135eaa83.png) + +## Global Flarum Updates +Simply runs the command `command update --prefer-dist --no-dev -a --with-all-dependencies`, useful for updating all packages. + +## Patch-Minor Flarum Updates +This changes directly required package versions to `*` and then executes the command `command update --prefer-dist --no-dev -a --with-all-dependencies`. + +![flarum lan_admin (5)](https://user-images.githubusercontent.com/20267363/135276114-ae438c2f-4122-45bd-b32f-690de3b56e25.png) + +## Major Flarum Updates +This changes directly required package versions to `*`, changes core to the latest major version requirement and then executes the same command above. Upon failure, it can be correctly guessed that some extensions are not compatible with the new major version, the exception details will include an array of extension package names that are not compatible, and it'll be rendered in the frontend, with the ability to run a `composer why-not flarum/core 2.0` for more details. + +![major update UI](https://user-images.githubusercontent.com/20267363/143277865-8323fa9a-c80f-4015-baca-fce4d2b5d585.png) + +## Flarum Updates (global, minor, major) +Information about the last updates ran are saved in a `last_update_run` JSON setting, which can contain an array of extension package names that didn't update to their latest version in the process, this is rendered in the frontend as warning icon buttons on the extension items, clicking on them will execute a `composer why-not`, displaying the details of the failure in a modal. + +![UI with list of extensions containing warning icon buttons](https://user-images.githubusercontent.com/20267363/143278774-6fada0da-dead-474b-8dfa-feda5021134f.png) ![UI with the modal showing the details](https://user-images.githubusercontent.com/20267363/143278786-d283db62-de96-4019-954e-932d0d6eac15.png) + +## Background Tasks +To get around timeout issues, composer commands can also run on the background use the queue. Users can be pointed towards [Blomstra's Database Queue Implementation](https://discuss.flarum.org/d/28151-database-queue-the-simplest-queue-even-for-shared-hosting) as a basic queue solution. It contains instructions on how to enable the queue through a cron job. + +:::danger Cron Job PHP Process Version + +It is common for shared hosts to have a low php version used in SSH, users must be pointed to the fact that they have to make sure the php process is of a version compatible with Flarum. Either by manually checking or by asking their hosts. + +::: + +![Extension Manager Queue Table Preview](/en/img/extension-manager-queue.png) + +## TODO +- Try on shared hosting. +- Better explanation on the UI about background tasks. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md new file mode 100644 index 000000000..067e2809f --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md @@ -0,0 +1,38 @@ +# PR Merging Policy + +Technical contributions to the Flarum source code go through a review process. Over the years we have tuned this process based on our experiences, our targeted development speed and availability. + +## What makes a great Pull Request? + +Great pull requests: + +- Have the [Pull Request template](https://github.com/flarum/.github/blob/main/PULL_REQUEST_TEMPLATE.md) filled out completely when opening a pull request. +- Do not combine different changes. Although tempting, don't change formatting of unrelated code. Stick to the one feature or change you wish to contribute. +- Have a related issue where the technical implementation has been agreed upon by the core team, or has been approved on by the core team through discussion on the official forums or other channels like Discord. +- Clearly explain the need for the change and list the areas where the pull request requires discussion. + +## Implementation Review Criteria + +- Adheres to our conventions or can be patched up easily after merging, follows proper code style. +- Are there any implementation details that could be done better through alternate technologies/technical approaches? +- Does not touch any lines outside of the intended changes, eg through formatting or compilation. +- If the changes are to code intended as a public API, has a proper doc block been included? + +## Merge Time! + +If all the checks in the template are met, **any** core developer may merge this PR. If the PR is authored by a core developer, they should probably be the ones to merge it. + +- Merging: + - GitHub offers several ways to merge a PR. Choose between the following strategies: + - **Merge** when the PR branch consists of atomic, well-described commits that are nice to have in the version history. + - **Squash** when lots of cleanup commits have accumulated. Please make sure to follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) spec for the squash commit. We usually find several commits from bots like StyleCI in these prefabricated commit messages, their commit messages should be removed. + +- After merging: + - Assign the related issue (if none exists, the pull request itself, but never both) to the appropriate milestone. + - Close all relevant issues (*if* they are closed completely). + - Regressions should be labeled as such and removed from the project board and milestone after merging. + - Check for follow-up tasks: + - Merge related PRs (language files, extensions, documentations). + - Documentation updates. + - Create issues for further follow-up tasks, if necessary. + diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/merging.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/merging.md new file mode 100644 index 000000000..0408b1bee --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/merging.md @@ -0,0 +1,29 @@ +# PR Merging Workflow + + +## Implementation Review Criteria + +- Adheres to our conventions or can be patched up easily after merging, follows proper code style. +- Are there any implementation details that could be done better through alternate technologies/technical approaches? +- Does not touch any lines outside of the intended changes, eg through formatting or compilation. +- If the changes are to code intended as a public API, has a proper doc block been included? + +## Merge Time! + +If all of the checks in the template are met, **any** core developer may merge this PR. If the PR is authored by a core developer, they should probably be the ones to merge it. + +- Merging: + - GitHub offers several ways to merge a PR. Choose between the following strategies: + - **Merge** when the PR branch consists of atomic, well-described commits that are nice to have in the version history. + - **Squash** when lots of cleanup commits have accumulated. Please make sure to follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) spec for the squash commit. + +- After merging: + - Make sure the *issue* (if none exists, the PR - but not both) belongs to the appropriate milestone and project board. + - PRs in extensions cannot be assigned to core milestones, so create a core issue that references it and add it to the milestone. + - Close all relevant issues (*if* they are closed completely). + - Regressions should be labeled as such and removed from the project board and milestone after merging. + - Check for follow-up tasks: + - Merge related PRs (language files, extensions, documentations). + - Documentation updates. + - Create issues for further follow-up tasks, if necessary. + diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md new file mode 100644 index 000000000..823599db5 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md @@ -0,0 +1,89 @@ +# Package Manager +This contains an explanation of how the package manager works and what it has to offer. + +## Contents +* Installing, Updating, and Removing Extensions. +* [Checking for Updates](#checking-for-updates). +* [Global Flarum Update](#global-flarum-updates). +* [Patch-Minor Flarum Updates](#patch-minor-flarum-updates). +* [Major Flarum Update](#major-flarum-updates). +* [Flarum Updates (global, minor, major)](#flarum-updates-global-minor-major). +* [Background Tasks](#background-tasks). + +## Requirements +There are some obstacles that need to be taken care of before this can be used. + +### File Permissions +The relevant machine web user needs to have permissions to read and write to: `vendor`, `composer.json`, `composer.lock` and `storage`. Right now a warning shows up when this is not the case, this should preferably be changed to mention only the files/dirs where permissions are lacking instead of all of them. + +![flarum lan_admin (3)](https://user-images.githubusercontent.com/20267363/135268536-f79d42ab-6e05-4e41-b2ab-d95ec7a8b021.png) + +### Path Repository +In development environments (and production in rare scenarios) there should a path repository to a directory containing (mostly dev) packages, the path to this directory must be changed to an absolute path otherwise composer will have trouble running any command. Additionally the path repository by default has higher priority, so requiring an extension that exists in that repository will probably fail, unless a `*@dev` constraint is specified, in which case the package manager should not be used for dev purposes anyway. + +There is currently now hint of any of this in the package manager UI. + +## Common Actions +Each one of the features listed above is basically a composer command or two, and there are common actions/common behaviour between them all. + +* Restricting access to the admin. +* Validating the provided package name or the extension id if given. +* Erroring out if installing an existing extension, updating or removing a non existing extension ...etc +* Running the command. This [auto logs the output](#command-output-logging). +* [Erroring out on command failure](#command-failure). +* Dispatching an event. +* If running an update: + + Clear Cache. + + Run Migrations. + + Publish Assets. + + Run an update check, and log any extensions that didn't update to their latest versions in the update process. + +### Command Output Logging +Considering this is still experimental and especially for the sake of easier support, each command output is logged to `storage/logs/composer` just like the flarum error logs, allowing to go back and see what happened during a command execution. + +### Command Failure +When a composer command fails (recognised by the exit code), an exception is thrown containing a reason guessed by the exception based on the command output text. Guessed causes render into proper explanatory alert messages on the frontend. + +## Checking for Updates +This executes the command `composer outdated -D --format json` which checks for updates of packages directly required in the root `composer.json` and outputs the results in JSON format. Only packages marked as `semver-safe-update` and `update-possible` by composer are displayed. + +The information about the last update check is saved into a JSON setting. + +![flarum lan_admin (4)](https://user-images.githubusercontent.com/20267363/135272032-9de37599-b364-4e42-b234-1113135eaa83.png) + +## Global Flarum Updates +Simply runs the command `command update --prefer-dist --no-dev -a --with-all-dependencies`, useful for updating all packages. + +## Patch-Minor Flarum Updates +This changes directly required package versions to `*` and then executes the command `command update --prefer-dist --no-dev -a --with-all-dependencies`. + +![flarum lan_admin (5)](https://user-images.githubusercontent.com/20267363/135276114-ae438c2f-4122-45bd-b32f-690de3b56e25.png) + +## Major Flarum Updates +This changes directly required package versions to `*`, changes core to the latest major version requirement and then executes the same command above. Upon failure, it can be correctly guessed that some extensions are not compatible with the new major version, the exception details will include an array of extension package names that are not compatible, and it'll be rendered in the frontend, with the ability to run a `composer why-not flarum/core 2.0` for more details. + +![major update UI](https://user-images.githubusercontent.com/20267363/143277865-8323fa9a-c80f-4015-baca-fce4d2b5d585.png) + +## Flarum Updates (global, minor, major) +Information about the last updates ran are saved in a `last_update_run` JSON setting, which can contain an array of extension package names that didn't update to their latest version in the process, this is rendered in the frontend as warning icon buttons on the extension items, clicking on them will execute a `composer why-not`, displaying the details of the failure in a modal. + +![UI with list of extensions containing warning icon buttons](https://user-images.githubusercontent.com/20267363/143278774-6fada0da-dead-474b-8dfa-feda5021134f.png) ![UI with the modal showing the details](https://user-images.githubusercontent.com/20267363/143278786-d283db62-de96-4019-954e-932d0d6eac15.png) + +## Background Tasks +To get around timeout issues, composer commands can also run on the background use the queue. Users can be pointed towards [Blomstra's Database Queue Implementation](https://discuss.flarum.org/d/28151-database-queue-the-simplest-queue-even-for-shared-hosting) as a basic queue solution. It contains instructions on how to enable the queue through a cron job. + +:::danger Cron Job PHP Process Version + +It is common for shared hosts to have a low php version used in SSH, users must be pointed to the fact that they have to make sure the php process is of a version compatible with Flarum. Either by manually checking or by asking their hosts. + +::: + +![Package Manager Queue Table Preview](/en/img/package-manager-queue.png) + +## TODO +- Try on shared hosting. +- Composer command job must not overlap. +- Code TODOs. +- Better explanation on the UI about background tasks. +- Take into consideration a scenario where we're updating an extension that isn't a root required dependency, like bundles. +- Run one background task at a time, prevent user from triggering multiple tasks. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/languages.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/languages.md new file mode 100644 index 000000000..d1e32af2a --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/languages.md @@ -0,0 +1,29 @@ +# Diller + +Temel Flarum kurulumunuza yeni bir dil eklemek kolaydır. Seçtiğiniz dil paketini indirmek ve kurmak için aşağıdaki talimatları uygulamanız yeterlidir. + +Bir dil paketi ekledikten sonra, forumunuz için [varsayılan dil olarak ayarlayabilirsiniz](#varsayılan-dili-ayarlama). Ve yüklü dil paketlerinizden birine ihtiyacınız olmadığını anlarsanız, her zaman \[devre dışı bırakabilirsiniz\] (#dil-paketini-devre-dışı-bırakma). Herhangi bir üçüncü taraf uzantısı kullanıyorsanız, başlamadan önce [bunu okuduğunuzdan](#topluluk-uzantıları) emin olun. + +## Dil Paketi Kurulumu + +Başlamak için, Flarum Community sitesinde [Extensions > Languages](https://discuss.flarum.org/t/languages) etiketini ziyaret edin ve yüklemek istediğiniz bir dil paketi bulun. + +Dil paketleri, [uzantılar](extensions.md) ile aynı şekilde yüklenir. Dil, yönetici arayüzünün **Uzantılar** sayfasında görünecektir ve orada etkinleştirebilirsiniz. + +Hepsi bu kadar! Artık forumunuzun görünümünü yeni dile geçirmek için sitenizin başlığındaki dil seçiciyi kullanabilmeniz gerekir. + +## Varsayılan Dili Ayarlama + +Bir dil paketi yükledikten ve çalıştığından emin olduktan sonra, onu yeni kullanıcılar ve misafirler için varsayılan dil olarak ayarlamak isteyebilirsiniz. Bunu yönetici arayüzünün **Temel Bilgiler** sayfasında yapabilirsiniz. + +## Dil Paketini Devre Dışı Bırakma + +Belirli bir dili desteklemenize gerek olmadığına karar verirseniz, sonuçta onu kapatabilirsiniz. Yönetici arayüzünün **Uzantılar** sayfasında dil paketini bulun ve devre dışı bırakın. + +Tek dilli bir site çalıştırıyorsanız ve dil seçicinin site başlığında görünmesini istemiyorsanız, bir dili devre dışı bırakmak yararlı olabilir. Dil seçici, yalnızca bir dil etkinleştirildiğinde gizlenir. + +## Topluluk Uzantıları + +Flarum Topluluğu sitesinden indirilen dil paketleri genellikle Flarum ile birlikte gelen tüm uzantıların çevirilerini içerecek olsa da, kural olarak yüklemiş olabileceğiniz tüm topluluk uzantılarını kapsamazlar. Uzantılarının çevirilerini sağlamak ve sürdürmek geliştiricilere bağlıdır. + +Bu nedenle, bir topluluk uzantısı yüklemeden önce, yüklediğiniz her dil paketi için çeviriler içerdiğinden emin olmalısınız. Bir uzantının ihtiyacınız olan bir dili desteklemediğini fark ederseniz, lütfen doğrudan geliştiriciyle iletişime geçin ve gerekli çevirilerin eklenmesini sağlayın. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/mail.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/mail.md new file mode 100644 index 000000000..e32384ac3 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/mail.md @@ -0,0 +1,29 @@ +# E-posta Yapılandırması + +Herhangi bir topluluğun, e-posta doğrulaması, şifre sıfırlama, bildirim ve kullanıcılara yönelik diğer iletişimlere izin vermek için e-posta göndermesi gerekir. Forumunuzu e-posta gönderecek şekilde yapılandırmak, yönetici olarak ilk adımlarınızdan biri olmalıdır: Yanlış bir yapılandırma, kullanıcılar kaydolmaya çalışırken hatalara neden olur. + +## Kullanılabilir Sürücüler + +Flarum varsayılan olarak birkaç sürücü sağlar, bunlar aşağıda listelenir ve açıklanır. Geliştiriciler ayrıca [uzantılar aracılığıyla özel posta sürücüleri](ext/mail.md) ekleyebilirler. + +### SMTP + +Bu muhtemelen en yaygın kullanılan e-posta sürücüsüdür ve harici bir SMTP hizmeti için bir ana bilgisayar, bağlantı noktası/şifreleme, kullanıcı adı ve şifre yapılandırmanıza izin verir. Lütfen şifreleme alanının `ssl` veya `tls` olmasını beklediğini unutmayın. + +### Posta + +`mail` sürücüsü, birçok barındırma sunucusunda bulunan sendmail/postfix e-posta sistemini kullanmaya çalışacaktır. Bunun çalışması için sendmail'i sunucunuza düzgün bir şekilde kurmanız ve yapılandırmanız gerekir. + +### Mailgun + +Bu sürücü, e-posta göndermek için [Mailgun](https://www.mailgun.com/) hesabınızı kullanır. Mailgun yapılandırmanızdaki etki alanı ve bölgenin yanı sıra gizli bir anahtara ihtiyacınız olacak. + +To use the mailgun driver, you'll need to install the Guzzle composer package (a PHP HTTP client). You can do this by running `composer require guzzlehttp/guzzle:^6.0|^7.0` in your Flarum install's root directory. + +### Günlük + +Günlük posta sürücüsü POSTA GÖNDERMEZ ve öncelikle geliştiriciler tarafından kullanılır. Herhangi bir e-postanın içeriğini `FLARUM_ROOT_DIRECTORY/storage/logs` içindeki günlük dosyasına yazar. + +## Test E-postası + +Bir e-posta yapılandırmasını kaydettikten sonra, yapılandırmanızın çalıştığından emin olmak için yönetici panosunun Posta sayfasındaki "Test Postası Gönder" düğmesini tıklayabilirsiniz. Bir hata görürseniz veya bir e-posta almazsanız, yapılandırmayı ayarlayın ve tekrar deneyin. Herhangi bir hata yoksa, ancak gelen kutunuzda hiçbir şey görünmüyorsa istenmeyen postanızı kontrol ettiğinizden emin olun. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/releases.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/releases.md new file mode 100644 index 000000000..2c9b883aa --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/releases.md @@ -0,0 +1,15 @@ +# Sürüm Notları + + + + +Sürüm notları [Flarum Topluluğu](https://discuss.flarum.org/t/blog?sort=newest)'nda bulunabilir. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/rest-api.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/rest-api.md new file mode 100644 index 000000000..10b1df14e --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/rest-api.md @@ -0,0 +1,375 @@ +# Consuming the REST API + +Flarum exposes a REST API which is used by the single page application but also available for external scripts. + +The API follows the best practices defined by the [JSON:API](https://jsonapi.org/) specification. + +:::bilgi + +To extend the REST API with new endpoints, see [API and Data Flow](extend/api.md) in the developer documentation. + +::: + +## Authentication + +The single page app uses session cookies to authenticate against the API. External scripts can use stateless authentication using [API Keys](#api-keys) or [Access Tokens](#access-tokens). + +`GET` endpoints can be used without authentication. Only content visible to guests will be returned. Other endpoints generally cannot be used without authentication because of the [CSRF protection](#csrf-protection). + +### API keys + +API Keys are the primary way for scripts, tools and integrations to interact with Flarum. + +#### Creation + +There is currently no UI to manage API Keys, but they can be created manually in the `api_keys` table of the database. + +The following attributes can be filled: + +- `key`: Generate a long unique token (recommended: alpha-numerical, 40 characters) and set it here, this will be the token used in the `Authorization` header. +- `user_id`: Optional. If set, the key can only be used to act as the given user. + +The remaining attributes are either automatically filled or currently not used: + +- `id`: Will be filled by MySQL auto-increment. +- `allowed_ips`: Not implemented. +- `scopes`: Not implemented. +- `created_at`: Can be set to any date, but is meant for the date of creation of the key. +- `last_activity_at`: Will be updated automatically when the token is used. + +#### Usage + +Attach your key value to each API request using the `Authorization` header. Then provide the user ID you want to interact as at the end of the header: + + Authorization: Token YOUR_API_KEY_VALUE; userId=1 + +If a `user_id` value has been set for the key in the database, `userId=` will be ignored. Otherwise, it can be set to any valid user ID that exists in the database. + +### Access Tokens + +Access Tokens are short-lived tokens that belong to a specific user. + +Those tokens are used behind the scenes for cookie sessions. Their use in stateless API requests has the same effect as a regular session. The user last activity will be updated each time the token is used. + +#### Creation + +All users are allowed to create access tokens. To create a token, use the `/api/token` endpoint with the credentials of your user: + +``` +POST /api/token HTTP/1.1 + +{ + "identification": "Toby", + "password": "pass7word" +} + +HTTP/1.1 200 OK + +{ + "token": "YACub2KLfe8mfmHPcUKtt6t2SMJOGPXnZbqhc3nX", + "userId": "1" +} +``` + +At the moment, 3 token types exist, although only 2 types can be created via the REST API. + +- `session` tokens expire after 1h of inactivity. This is the default token type. +- `session_remember` tokens expire after 5 years of inactivity. They can be obtained by specifying `remember=1` in the request attributes. +- `developer` tokens never expire. They can only be created manually in the database at the moment. + +**All access tokens are deleted when the user logs out** (this includes `developer` tokens, although it is planned to change it). + +#### Usage + +Attach the returned `token` value to each API request using the `Authorization` header: + + Authorization: Token YACub2KLfe8mfmHPcUKtt6t2SMJOGPXnZbqhc3nX + +### CSRF Protection + +Most of the `POST`/`PUT`/`DELETE` API endpoints are protected against [Cross-site request forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery). This means stateless requests are not possible without authentication. + +When using an API Key or Access Token, CSRF protection is bypassed. + +## Endpoints + +This part of the documentation is still in progress. We are researching options to provide an automated documentation of the endpoints. + +Every extension adds new endpoints and attributes so it's difficult to provide a complete documentation of all endpoints. A good way to discover endpoints is to use the browser development tools to inspect requests made by the single page application. + +Below are a few examples of commonly used endpoints. JSON has been truncated to make reading easier. + +### List discussions + + GET /api/discussions + +```json +{ + "links": { + "first": "https://flarum.tld/api/discussions", + "next": "https://flarum.tld/api/discussions?page%5Boffset%5D=20" + }, + "data": [ + { + "type": "discussions", + "id": "234", + "attributes": { + "title": "Lorem Ipsum", + "slug": "234-lorem-ipsum", + "commentCount": 10, + "participantCount": 3, + "createdAt": "2022-01-01T10:20:30+00:00", + "lastPostedAt": "2022-01-05T10:20:30+00:00", + "lastPostNumber": 10, + "canReply": true, + "canRename": true, + "canDelete": true, + "canHide": true, + "isHidden": true, + "hiddenAt": "2022-01-06T10:20:30+00:00", + "lastReadAt": "2022-01-02T10:20:30+00:00", + "lastReadPostNumber": 2, + "isApproved": true, + "canTag": true, + "isLocked": false, + "canLock": true, + "isSticky": false, + "canSticky": true, + "canMerge": true, + "subscription": null + }, + "relationships": { + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + "lastPostedUser": { + "data": { + "type": "users", + "id": "64" + } + }, + "tags": { + "data": [ + { + "type": "tags", + "id": "3" + } + ] + }, + "firstPost": { + "data": { + "type": "posts", + "id": "668" + } + } + } + }, + { + "type": "discussions", + "id": "234", + "attributes": { + // [...] + }, + "relationships": { + // [...] + } + }, + // [...] more discussions + ], + "included": [ + { + "type": "users", + "id": "1", + "attributes": { + "username": "Admin", + "displayName": "Admin", + "avatarUrl": null, + "slug": "1" + } + }, + { + "type": "users", + "id": "64", + "attributes": { + "username": "Flarum", + "displayName": "Flarum", + "avatarUrl": "https://flarum.tld/assets/avatars/Z4hEncw0ndVqZ8be.png", + "slug": "64" + } + }, + { + "type": "tags", + "id": "3", + "attributes": { + "name": "Welcome", + "description": "Post interesting things here", + "slug": "welcome", + "color": "#888", + "backgroundUrl": null, + "backgroundMode": null, + "icon": "fas fa-bullhorn", + "discussionCount": 30, + "position": 1, + "defaultSort": null, + "isChild": false, + "isHidden": false, + "lastPostedAt": "2022-01-05T10:20:30+00:00", + "canStartDiscussion": true, + "canAddToDiscussion": true, + "isRestricted": false + } + }, + { + "type": "posts", + "id": "668", + "attributes": { + "number": 1, + "createdAt": "2022-01-01T10:20:30+00:00", + "contentType": "comment", + "contentHtml": "

Hello World

" + } + }, + // [...] more includes for the other discussions + ] +} +``` + +### Create discussion + + POST /api/discussions + +```json +{ + "data":{ + "type": "discussions", + "attributes": { + "title": "Lorem Ipsum", + "content": "Hello World" + }, + "relationships": { + "tags": { + "data": [ + { + "type": "tags", + "id": "1" + } + ] + } + } + } +} +``` + +The response includes the ID of the new discussion: + +```json +{ + "data": { + "type": "discussions", + "id": "42", + "attributes": { + "title": "Lorem Ipsum", + "slug": "42-lorem-ipsum", + "commentCount": 1 + // [...] other attributes + }, + "relationships": { + "posts": { + "data": [ + { + "type": "posts", + "id": "58" + } + ] + }, + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + // [...] other relationships + } + }, + "included":[ + { + "type": "posts", + "id": "38", + "attributes": { + "number": 1, + "contentType": "comment", + "contentHtml": "\u003Cp\u003EHello World\u003C\/p\u003E" + // [...] other attributes + } + } + // [...] other includes + ] +} +``` + +### Create user + + POST /api/users + +```json +{ + "data": { + "attributes": { + "username": "Flarum", + "email": "flarum@example.com", + "password": "correcthorsebatterystaple" + } + } +} +``` + +## Errors + +Flarum uses various HTTP status code and includes error descriptions that follow the [JSON:API error spec](https://jsonapi.org/format/#errors). + +Below are a few common errors you might encounter when using the REST API: + +### CSRF Token Mismatch + +If you receive a 400 HTTP error with `csrf_token_mismatch` message, it means the `Authorization` header is absent or invalid and Flarum attempted to authenticate through the session cookie. + +```json +{ + "errors": [ + { + "status": "400", + "code": "csrf_token_mismatch" + } + ] +} +``` + +### Validation errors + +Validation errors are returned with 422 HTTP status code. The name of the invalid field is returned as the `pointer` value. There can be multiple errors for a single field at the same time. + +```json +{ + "errors": [ + { + "status": "422", + "code": "validation_error", + "detail": "The username has already been taken.", + "source":{ + "pointer":"\/data\/attributes\/username" + } + }, + { + "status": "422", + "code": "validation_error", + "detail": "The email has already been taken.", + "source": { + "pointer":"\/data\/attributes\/email" + } + } + ] +} +``` diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/scheduler.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/scheduler.md new file mode 100644 index 000000000..6123ce7c3 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/scheduler.md @@ -0,0 +1,55 @@ +# Scheduler + +The Flarum scheduler allows extensions to automate certain tasks effortlessly. In this guide we will see how to set it up. We won't go into the details of cron itself, but if you want to read more about it, I suggest you take a look at [this Wikipedia article](https://en.wikipedia.org/wiki/Cron) on cron. + +## Why should I care? + +Quite simply, a growing list of extensions now support handling certain functions automatically for you, completely behind the scenes. Wondering why `fof/drafts` 'scheduled drafts' are not posting, or `fof/best-answer` 'remind users to set a best answer after X days' does not fire? That'll be because they will setup themselves with the scheduler service, but without a one-liner cron job, nothing will happen! + +## What extensions currently use the scheduler? + +Some of the most popular examples are the following: + +- [FoF Best Answer](https://github.com/FriendsOfFlarum/best-answer) +- [FoF Drafts](https://github.com/FriendsOfFlarum/drafts) +- [FoF Sitemap](https://github.com/FriendsOfFlarum/sitemap) +- [FoF Open Collective](https://github.com/FriendsOfFlarum/open-collective) +- [FoF Github Sponsors](https://github.com/FriendsOfFlarum/github-sponsors) + +## Ok, let's get this setup! + +Most (if not all) Linux distros either come with, or can have, cron installed. For example, on Debian and Ubuntu based systems, you can install `cron` like this: + +``` +sudo apt-get update +sudo apt-get install cron +``` + +In case you are using a RHEL based Linux distribution (CentOS, AlmaLinux, Rocky Linux...), install cron like this: + +``` +sudo dnf update +sudo dnf install crontabs +``` + +Once you have cron installed, let's create the one and only entry you need for Flarum: + +``` +crontab -e +``` + +This will open the cron editor. You may or may not have other entries there. Add this line, and remember to leave an empty line at the bottom. + +``` +* * * * * cd /path-to-your-project && php flarum schedule:run >> /dev/null 2>&1 +``` + +`* * * * *` tells cron to run your command every minute. + +In case you want to use a different value and don't know exactly how cron expressions work, you can use a [cron expression generator](https://crontab.guru) to easily get the desired string. + +`cd /path-to-your-project && php flarum schedule:run` executes Flarum's scheduler to trigger any tasks currently waiting to be run. If PHP isn't in your system's path, you may need to experiment with setting the full path to PHP. + +Lastly `>> /dev/null 2>&1` suppresses any output from the command. + +Voila! Now any extension that registers a task to run, anything from every minute to daily, monthly, yearly - whatever - will now run on your server. diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/themes.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/themes.md new file mode 100644 index 000000000..97e8e6730 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/themes.md @@ -0,0 +1,29 @@ +# Tema + +Flarum'u olabildiğince güzel hale getirmek için çok çalışmış olsak da, her topluluk muhtemelen arzu ettikleri stile uyacak bazı ince ayarlar/değişiklikler yapmak isteyecektir. + +## Yönetici Gösterge Paneli + +[Yönetici gösterge tablosu](admin.md)'nun Görünüm sayfası, forumunuzu özelleştirmeye başlamak için harika bir ilk yerdir. Burada yapabilirsin: + +- Tema renklerini seçin +- Karanlık modu ve renkli üstbilgi değiştir +- Bir logo ve favicon yükleyin (tarayıcı sekmelerinde gösterilen simge) +- Özel üstbilgiler ve altbilgiler için HTML ekleyin +- Öğelerin görüntülenme şeklini değiştirmek için [özel LESS/CSS](#css-theming) ekleyin + +## CSS Tema Oluşturma + +CSS, tarayıcılara bir web sayfasının öğelerinin nasıl görüntüleneceğini söyleyen bir stil sayfası dilidir. Renklerden yazı tiplerine, eleman boyutuna ve konumlandırmadan animasyonlara kadar her şeyi değiştirmemizi sağlar. Özel CSS eklemek, Flarum kurulumunuzu bir temayla eşleşecek şekilde değiştirmenin harika bir yolu olabilir. + +Bir CSS eğitimi bu belgesinin kapsamı dışındadır, ancak CSS'nin temellerini öğrenmek için birçok harika çevrimiçi kaynak vardır. + +:::tip + +Flarum aslında LESS kullanır, bu da değişkenlere, koşullara ve işlevlere izin vererek CSS yazmayı kolaylaştırır. + +::: + +## Uzantılar + +Flarum'un esnek [uzantı sistemi](extensions.md), Flarum'un herhangi bir parçasını pratik olarak eklemenize, çıkarmanıza veya değiştirmenize olanak tanır. Renkleri/boyutları/stilleri değiştirmenin ötesinde önemli tema değişiklikleri yapmak istiyorsanız, kesinlikle gitmenin yolu özel bir uzantıdır. Bir uzantının nasıl oluşturulacağını öğrenmek için [uzantı belgelerimize](extend/README.md) göz atın! diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md new file mode 100644 index 000000000..312c3e286 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md @@ -0,0 +1,56 @@ +# Sorun Giderme + +Flarum beklendiği gibi yüklenmiyorsa veya çalışmıyorsa, yapmanız gereken ilk şey ortamınızın [sistem gereksinimlerini](install.md#sunucu-gereksinimleri) karşılayıp karşılamadığını *tekrar kontrol etmektir.* Flarum'un çalıştırması gereken bir şeyi kaçırıyorsanız, onu düzeltmeniz gerekir. If you're missing something that Flarum needs to run, you'll need to remedy that first. + +Ayrıca, [Destek forumunu](https://discuss.flarum.org/t/support) ve [sorun izleyiciyi](https://github.com/flarum/core/issues) aramak için birkaç dakikanızı ayırmalısınız. Birisi sorunu zaten bildirmiş olabilir ve bir düzeltme mevcut veya yolda. İyice araştırdıysanız ve sorunla ilgili herhangi bir bilgi bulamıyorsanız, sorun gidermeye başlamanın zamanı geldi. + +## Step 0: Activate debug mode + +:::danger Skip on Production + +These debugging tools are very useful, but can expose information that shouldn't be public. These are fine if you're on a staging or development environment, but if you don't know what you're doing, skip this step when on a production environment. + +::: + +Devam etmeden önce, Flarum'un hata ayıklama araçlarını etkinleştirmelisiniz. Basitçe bir metin düzenleyiciyle **config.php** açın, `debug` değerini `true` olarak değiştirin ve dosyayı kaydedin. Bu, Flarum'un ayrıntılı hata mesajları göstermesine neden olarak size neyin yanlış gittiğine dair bir fikir verecektir. + +Boş sayfalar görüyorsanız ve yukarıdaki değişiklik yardımcı olmuyorsa, **php.ini** yapılandırma dosyanızda `display_errors` ı `On` olarak ayarlamayı deneyin. + +## 1. Adım: Yaygın düzeltmeler + +A lot of issues can be fixed with the following: + +* Tarayıcınızın önbelleğini temizleyin +* Arka uç önbelleğini [`php flarum cache:clear`](console.md) ile temizleyin. +* Veritabanınızın [`php flarum migrate`](console.md) ile güncellendiğinden emin olun. +* Yönetici panonuzdaki [e-posta yapılandırmasının](mail.md) doğru olduğundan emin olun: geçersiz e-posta yapılandırması kayıt olurken, parolayı sıfırlarken, e-postaları değiştirirken ve bildirim gönderirken hatalara neden olur. +* `config.php` dosyanızın doğru olup olmadığını kontrol edin. Örneğin, doğru `url` nin kullanıldığından emin olun. +* One potential culprit could be a custom header, custom footer, or custom LESS. If your issue is in the frontend, try temporarily removing those via the Appearance page of the admin dashboard. + +Ayrıca önemli hiçbir şeyin yerinde olmadığından emin olmak için [`php flarum info`](console.md) çıktısına da göz atmak isteyeceksiniz. + +## 2. Adım: Sorunu yeniden oluşturun + +Sorunun yeniden oluşmasını sağlamaya çalışın. Gerçekleştiğinde ne yaptığınıza dikkat edin. Her seferinde mi yoksa sadece ara sıra mı oluyor? Sorunu etkileyebileceğini düşündüğünüz bir ayarı veya bir şeyleri yaptığınız sırayı değiştirmeyi deneyin. Bazı koşullarda olurken diğerleri olmuyor mu? + +Yakın zamanda bir uzantı eklediyseniz veya güncellediyseniz, sorunun çözülüp çözülmediğini görmek için geçici olarak devre dışı bırakmalısınız. Tüm uzantılarınızın, çalıştırdığınız Flarum sürümüyle kullanılmak üzere tasarlandığından emin olun. Eski uzantılar, çeşitli sorunlara neden olabilir. + +Yol boyunca bir yerlerde sorununuza neyin sebep olduğu hakkında bir fikir edinebilir ve bunu düzeltmenin bir yolunu bulabilirsiniz. Ancak bu olmasa bile, hata raporunuzu doldurduktan sonra, neler olup bittiğini anlamamıza yardımcı olacak birkaç değerli ipucuyla karşılaşacaksınız. + +## 3. Adım: Bilgi toplayın + +Sorunu çözmek için yardıma ihtiyacınız olacak gibi görünüyorsa, veri toplama konusunda ciddi olmanın zamanı geldi. Aşağıdaki yerlerde hata mesajlarını veya sorunla ilgili diğer bilgileri arayın: + +* Asıl sayfada görüntülenir +* Tarayıcı konsolunda görüntülenir (Chrome: Diğer araçlar -> Geliştirici Araçları -> Konsol) +* `/var/log/nginx/error.log`) +* PHP-FPM'nin hata günlüğüne kaydedilir (ör. `/var/log/php7.x-fpm.log`) +* Flarum tarafından kaydedildi (`storage/logs/flarum.log`) + +Herhangi bir mesajı bir metin dosyasına kopyalayın ve hatanın *ne zaman* oluştuğu, o sırada *ne yaptığınız* vb. Hakkında birkaç not alın. Sorunun meydana geldiği ve oluşmadığı koşullar hakkında derlemiş olabileceğiniz tüm bilgileri eklediğinizden emin olun. Sunucu ortamınız hakkında olabildiğince fazla bilgi ekleyin: İşletim sistemi sürümü, web sunucusu sürümü, PHP sürümü ve işleyici, vb. + +## 4. Adım: Bir rapor hazırlayın + +Sorunla ilgili tüm bilgileri topladıktan sonra bir hata raporu vermeye hazırsınız. Lütfen [Hataları Bildirme](bugs.md) ile ilgili talimatları uygulayın. + +Raporunuzu doldurduktan sonra sorunla ilgili yeni bir şey keşfederseniz, lütfen bu bilgiyi orijinal yayınınızın altına ekleyin. Sorunu kendi başınıza çözmüş olsanız bile rapor vermek iyi bir fikirdir, çünkü diğer kullanıcılar da çözümünüzden faydalanabilir. Sorun için geçici bir çözüm bulduysanız, bundan da bahsettiğinizden emin olun. \ No newline at end of file diff --git a/i18n/tr/docusaurus-plugin-content-docs/version-1.x/update.md b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/update.md new file mode 100644 index 000000000..74eb08c71 --- /dev/null +++ b/i18n/tr/docusaurus-plugin-content-docs/version-1.x/update.md @@ -0,0 +1,110 @@ +# Güncelleme + +## From the Admin Dashboard + +:::bilgi + +If you have the extension manager extension installed you can simply run the update from its interface and skip this page entirely. + +::: + +--- + +Flarum'u güncellemek için [Composer](https://getcomposer.org) kullanmanız gerekir. Eğer aşina değilseniz (Flarum'u kurmak için buna ihtiyacınız vardır), ne olduğu ve nasıl kurulacağı hakkında bilgi için [kılavuzumuzu](composer.md) okuyun. + +Ana sürümler arasında güncelleme yapıyorsanız (ör. <=0.1.0 - 1.x.x, 1.x.x - 2.x.x, ...), genel yükseltme adımlarını çalıştırmadan önce uygun "ana sürüm güncelleme kılavuzunu" okuduğunuzdan emin olun. + +## Genel Adımlar + +**1. Adım:** Tüm uzantılarınızın, yüklemeye çalıştığınız Flarum sürümüyle uyumlu sürümleri olduğundan emin olun. Bu yalnızca ana sürümler için gereklidir (örneğin, uzantılarınızın önerilen sürümü izlediğini varsayarsak, v1.0.0'dan v1.1.0'a yükseltme yapıyorsanız muhtemelen bunu kontrol etmeniz gerekmez). Bunu, uzantının [Tartışma konusuna](https://discuss.flarum.org/t/extensions) bakarak, [Packagist](http://packagist.org/)'te arayarak veya [Extiverse](https://extiverse.com) gibi veritabanlarını kontrol ederek bilgi alabilirsiniz. Güncellemeden önce uyumsuz uzantıları kaldırmanız (yalnızca devre dışı bırakmanız değil) gerekir. Lütfen uzantı geliştiricilerine karşı sabırlı olun! + +**2. Adım:** `composer.json` dosyanıza bir göz atın. Uzantıların veya kitaplıkların belirli sürümlerini gerektirecek bir nedeniniz yoksa, `flarum/core` dışındaki her şeyin sürüm dizesini `*` olarak ayarlamalısınız ((`flarum/tags dahil) `, `flarum/bahsetmeler` ve diğer paket uzantılar.) `flarum/core` öğesinin `*` olarak AYARLANMADIĞINDAN emin olun. Belirli bir Flarum sürümünü hedefliyorsanız, `flarum/core` öğesini buna ayarlayın (ör. `"flarum/core": "v0.1.0-beta.16`). Yalnızca en son sürümü istiyorsanız, `"flarum/core": "^1.0"` kullanın. + +**3. Adım:** Yerel kurulumunuz [yerel genişleticiler](extenders.md) kullanıyorsa, bunların Flarum'daki değişikliklerle güncel olduğundan emin olun. + +**4. Adım:** Güncellemeden önce yönetici kontrol panelinde üçüncü taraf uzantıları devre dışı bırakmanızı öneririz. Bu kesinlikle gerekli değildir, ancak sorunlarla karşılaşırsanız hata ayıklamayı kolaylaştıracaktır. + +**Adım 5:** PHP sürümünüzün yükseltmeye çalıştığınız Flarum sürümü tarafından desteklendiğinden ve Composer 2'yi (`composer --version)` kullandığınızdan emin olun. + +**6. Adım:** Son olarak, güncellemek için şunu çalıştırın: + +``` +composer update --prefer-dist --no-plugins --no-dev -a --with-all-dependencies +php flarum migrate +php flarum cache:clear +``` + +**Adım 7:** Varsa, PHP işleminizi ve opcache'nizi yeniden başlatın. + +## Ana Sürüm Güncelleme Kılavuzları + +### Beta'dan (<=0.1.0) Kararlı v1'e (^1.0.0) güncelleme + +1. Yukarıdaki 1-5 adımlarını uygulayın. +2. `Composer.json`'da tüm paketlenmiş uzantıların (`flarum/tags`, `flarum/bahsetme`, `flarum/likes` vb.) sürüm dizelerini değiştirin. `^0.1.0` ile `*` arasında değişti. +3. `composer.json` içindeki `flarum/core` sürüm dizesini `^0.1.0`'den `^1.0`'e değiştirin. +4. `composer.json` dosyanızdan `"minimum-stability": "beta",` satırını kaldırın +5. Yukarıdaki 6. ve 7. adımları uygulayın. + +## Sorun Giderme + +Flarum'u güncellerken hatalarla karşılaşabileceğiniz 2 ana yer vardır: Güncelleme komutunu çalıştırırken veya güncellemeden sonra foruma erişirken. + +### Güncelleme Sırasında Oluşan Hatalar + +Burada, Flarum'u güncellemeye çalışırken sık karşılaşılan birkaç sorun türünü inceleyeceğiz. + +--- + +Çıktı kısaysa ve şunları içeriyorsa: + +``` +Nothing to modify in lock file +``` + +Veya `flarum/core`'u güncellenmiş bir paket olarak listelemiyor ve en son flarum sürümünü kullanmıyorsunuz: + +- Yukarıdaki 2. adımı tekrar gözden geçirin, tüm üçüncü taraf uzantılarının sürüm dizelerinde bir yıldız işaretine sahip olduğundan emin olun. +- Make sure your `flarum/core` version requirement isn't locked to a specific minor version (e.g. `v0.1.0-beta.16` is locked, `^1.0.0` isn't). If you're trying to update across major versions of Flarum, follow the related major version update guide above. + +--- + +For other errors, try running `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO` + +If the output looks something like this: + +``` +flarum/flarum - requires flarum/core (v0.1.0-beta.15) +fof/moderator-notes 0.4.4 requires flarum/core (>=0.1.0-beta.15 <0.1.0-beta.16) +jordanjay29/flarum-ext-summaries 0.3.2 requires flarum/core (>=0.1.0-beta.14 <0.1.0-beta.16) +flarum/core v0.1.0-beta.16 requires dflydev/fig-cookies (^3.0.0) +flarum/flarum - does not require dflydev/fig-cookies (but v2.0.3 is installed) +flarum/core v0.1.0-beta.16 requires franzl/whoops-middleware (^2.0.0) +flarum/flarum - does not require franzl/whoops-middleware (but 0.4.1 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/bus (^8.0) +flarum/flarum - does not require illuminate/bus (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/cache (^8.0) +flarum/flarum - does not require illuminate/cache (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/config (^8.0) +flarum/flarum - does not require illuminate/config (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/container (^8.0) +flarum/flarum - does not require illuminate/container (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/contracts (^8.0) +flarum/flarum - does not require illuminate/contracts (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/database (^8.0) +flarum/flarum - does not require illuminate/database (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/events (^8.0) +flarum/flarum - does not require illuminate/events (but v6.20.19 is installed) +... (this'll go on for a bit) +``` + +It is very likely that some of your extensions have not yet been updated. + +- Revisit step 1 again, make sure all your extensions have versions compatible with the core version you want to upgrade to. Remove any that don't. +- Make sure you're running `composer update` with all the flags specified in the update step. + +If none of this fixes your issue, feel free to reach out on our [Support forum](https://discuss.flarum.org/t/support). Make sure to include the output of `php flarum info` and `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO`. + +### Errors After Updating + +If you are unable to access your forum after updating, follow our [troubleshooting instructions](troubleshoot.md). diff --git a/i18n/vi/docusaurus-plugin-content-docs/current.json b/i18n/vi/docusaurus-plugin-content-docs/current.json index 23152dfb5..15c22ad1e 100644 --- a/i18n/vi/docusaurus-plugin-content-docs/current.json +++ b/i18n/vi/docusaurus-plugin-content-docs/current.json @@ -1,6 +1,6 @@ { "version.label": { - "message": "Tiếp theo", + "message": "2.x", "description": "The label for version current" }, "sidebar.guideSidebar.category.Introduction": { @@ -39,4 +39,4 @@ "message": "Tài liệu nội bộ", "description": "The label for category Internal Docs in sidebar internalSidebar" } -} \ No newline at end of file +} diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/README.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/README.md new file mode 100644 index 000000000..62d814c21 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/README.md @@ -0,0 +1,45 @@ +- - - +slug: / +- - - + +# Về Flarum + +Flarum là một nền tảng thảo luận đơn giản thú vị cho trang web của bạn. Nó nhanh chóng, miễn phí và dễ sử dụng, với tất cả các tính năng bạn cần để điều hành một cộng đồng thành công. Nó cũng cực kỳ có thể mở rộng, cho phép khả năng tùy chỉnh cao nhất. + +![Ảnh chụp màn hình Trang chủ Flarum](/en/img/home_screenshot.png) + +## Mục tiêu + +Flarum là sự kế thừa kết hợp của [esoTalk](https://github.com/esotalk/esoTalk) và [FluxBB](https://fluxbb.org). Nó được thiết kế để: + +* **Nhanh chóng và đơn giản.** Không lộn xộn, không cồng kềnh, không phụ thuộc phức tạp. Flarum được xây dựng bằng PHP để triển khai nhanh chóng và dễ dàng. Giao diện được cung cấp bởi [Mithril](https://mithril.js.org), một khung JavaScript hiệu quả với một dấu ấn nhỏ. + +* **Đẹp và nhanh nhạy.** Đây là phần mềm diễn đàn dành cho con người. Flarum được thiết kế cẩn thận để nhất quán và trực quan trên các nền tảng, ngay từ đầu. + +* **Mạnh mẽ và có thể mở rộng.** Tùy chỉnh, mở rộng và tích hợp Flarum cho phù hợp với cộng đồng của bạn. Kiến trúc của Flarum rất linh hoạt, với [API tiện ích mở rộng mạnh mẽ](/extend/README.md). + +* **Miễn phí và mở.** Flarum được phát hành theo [giấy phép MIT](https://github.com/flarum/flarum/blob/master/LICENSE). + +Bạn có thể đọc thêm về [triết lý và giá trị của chúng tôi đối với Flarum tại đây](https://discuss.flarum.org/d/28869-flarum-philosophy-and-values). + +## Trợ giúp dự án Flarum + +Flarum là phần mềm [miễn phí, mã nguồn mở](https://github.com/flarum/core), được duy trì và quản lý bởi các tình nguyện viên. Chúng tôi dựa vào sự đóng góp của cộng đồng để giúp chúng tôi cải thiện và mở rộng Flarum. + +🧑‍💻 Nếu bạn là nhà phát triển, hãy xem xét [đóng góp vào các tiện ích mở rộng cốt lõi hoặc đi kèm của Flarum](contributing.md). Đây là **cách** hiệu quả nhất để trợ giúp Flarum và công việc của bạn có thể có nhiều tác động: có hàng nghìn trang web Flarum trên mạng, với tổng số hàng triệu người dùng cuối. + +🧩 Nếu thiếu tính năng bạn đang tìm kiếm hoặc ý tưởng chủ đề bạn có, [viết một phần mở rộng tùy chỉnh](extend/README.md) sẽ làm cho Flarum tốt hơn nhiều cho bạn và những người khác. + +✒️ Nếu bạn có kinh nghiệm viết kỹ thuật, hãy đóng góp cho [tài liệu của chúng tôi](https://github.com/flarum/docs/issues) có thể giúp người dùng, quản trị viên và nhà phát triển trong tương lai tận dụng tối đa Flarum. + +🌐 Nếu bạn thông thạo được nhiều ngôn ngữ, bạn có thể [đóng góp bản dịch](extend/language-packs.md) để giúp Flarum tiếp cận đến được nhiều người trên thế giới hơn. + +💸 Flarum Foundation không kiếm tiền từ Flarum, nhưng có hóa đơn thanh toán. Các khoản đóng góp qua [Nhà tài trợ GitHub](https://github.com/sponsors/flarum) hoặc [OpenCollective](https://opencollective.com/flarum) luôn luôn đã nhận một cách biết ơn. Trước đây, chúng tôi cũng đã có thể hỗ trợ tài chính cho một số nhà phát triển cốt lõi của mình, để họ có thể làm việc bán thời gian trên Flarum. Điều này sẽ không thể thực hiện được nếu không có sự hỗ trợ tài chính của bạn. + +🧑‍🤝‍🧑 Tham gia [cộng đồng của chúng tôi](https://discuss.flarum.org) để nói về sự phát triển của Flarum, nhận trợ giúp về phiên bản của bạn hoặc gặp gỡ những người thú vị! Nếu bạn có kinh nghiệm với Flarum, bạn cũng có thể giúp đỡ những người mới bắt đầu! + +🐛 Nếu có một lỗi nào đó đang làm phiền bạn hoặc bạn nảy ra ý tưởng về tính năng, chúng tôi không thể biết về nó trừ khi bạn cho chúng tôi biết! Chúng tôi theo dõi các lỗi, đề xuất và kế hoạch phát triển trong tương lai [thông qua các vấn đề GitHub](https://github.com/flarum/core/issues). Nếu đã có một vấn đề đang mở, việc thêm lượt thích và thông tin bổ sung (mang tính xây dựng) có thể rất hữu ích! + +📣 Và nếu bạn thích Flarum, hãy cân nhắc viết blog/tweet/nói về nó! Nhiều người biết đến Flarum hơn dẫn đến nhiều người tương tác với Flarum hơn, và do đó có nhiều hoạt động hơn, tiện ích mở rộng tốt hơn và phát triển nhanh hơn. + +Flarum sẽ không thể thực hiện được nếu không có cộng đồng hiện tượng của chúng tôi. Nếu bạn muốn đóng góp, hãy xem tài liệu [đóng góp của nhà phát triển](contributing.md) và [đóng góp khác](contributing-docs-translations.md) của chúng tôi để biết thêm thông tin. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/admin.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/admin.md new file mode 100644 index 000000000..b3fae602f --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/admin.md @@ -0,0 +1,13 @@ +# Trang tổng quan quản trị + +Bảng điều khiển quản trị Flarum là một giao diện thân thiện với người dùng để quản lý diễn đàn của bạn. Nó chỉ khả dụng cho người dùng trong nhóm "Quản trị viên". Để truy cập trang Quản trị, nhấn vào **Tên** của bạn ở trên cùng bên phải của màn hình và chọn **Trang quản trị**. + +Bảng điều khiển dành cho quản trị viên gồm các phần sau: +- **Trang tổng quan** - Hiển thị Trang tổng quan quản trị chính, chứa số liệu thống kê và thông tin có liên quan khác. +- **Cơ bản** - Hiển thị các tùy chọn để đặt các chi tiết cơ bản của diễn đàn như Tên, Mô tả và Biểu ngữ chào mừng. +- **Email** - Cho phép bạn định cấu hình cài đặt E-Mail của mình. Tham khảo [tại đây](https://docs.flarum.org/mail) để biết thêm thông tin. +- **Quyền** - Hiển thị các quyền cho từng nhóm người dùng và cho phép bạn định cấu hình phạm vi toàn cầu và phạm vi cụ thể. +- **Giao diện** - Cho phép bạn tùy chỉnh màu sắc, thương hiệu của diễn đàn và thêm CSS bổ sung để tùy chỉnh. +- **Người dùng** - Cung cấp cho bạn danh sách được phân trang gồm tất cả người dùng trong diễn đàn và cấp cho bạn khả năng chỉnh sửa người dùng hoặc thực hiện các hành động quản trị. + +Ngoài các phần được đề cập ở trên, Trang tổng quan quản trị cũng cho phép bạn quản lý các Tiện ích mở rộng của mình (bao gồm các tiện ích mở rộng cốt lõi như Thẻ) trong phần _Tính năng_. Các tiện ích mở rộng sửa đổi chủ đề diễn đàn hoặc cho phép bạn sử dụng nhiều ngôn ngữ được phân loại trong phần _Chủ đề_ và _Ngôn ngữ_ tương ứng. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/bugs.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/bugs.md new file mode 100644 index 000000000..4736c745c --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/bugs.md @@ -0,0 +1,28 @@ +# Báo cáo lỗi + +:::danger Lỗ hổng bảo mật + +Nếu bạn phát hiện ra lỗ hổng bảo mật trong Flarum, vui lòng tuân theo[chính sách bảo mật](https://github.com/flarum/core/security/policy) của chúng tôi để chúng tôi có thể giải quyết kịp thời. + +::: + +Cảm ơn bạn đã giúp chúng tôi kiểm tra Flarum. Chúng tôi rất vui khi có bạn trong nhóm! Chúng tôi cần những người có thể *kiên nhẫn khắc phục sự cố* và *thông báo rõ ràng*. Như bạn có thể biết, báo cáo lỗi tốt cần một chút thời gian và nỗ lực. Nếu bạn ổn với điều đó, thì hãy bắt đầu! + +## Trùng lặp + +Đã tìm thấy một lỗi? Tuyệt vời! Chúng tôi rất muốn nghe về nó — nhưng trước tiên, bạn nên kiểm tra xung quanh để đảm bảo rằng bạn không lãng phí thời gian vào một vấn đề đã biết: + +- Tìm kiếm trong [Diễn đàn hỗ trợ](https://discuss.flarum.org/t/support) của chúng tôi để xem liệu nó đã được báo cáo chưa. +- Chúng tôi có thể đang tìm cách khắc phục, vì vậy hãy tìm kiếm trong [trình theo dõi sự cố](https://github.com/flarum/core/issues) của chúng tôi. + +Nếu bạn đã tìm kiếm *ỹ lưỡng* và ra về tay không, chúng tôi sẽ hoan nghênh báo cáo của bạn. Nếu đó chỉ là một vấn đề đơn giản (ví dụ: một từ sai chính tả hoặc trục trặc đồ họa), hãy chuyển sang đoạn tiếp theo. Nhưng nếu bạn thấy lỗi hoặc một cái gì đó rõ ràng bị hỏng, chúng tôi sẽ cần bạn thu thập một số thông tin trước. Vui lòng xem hướng dẫn [Gỡ rối](troubleshoot.md) của chúng tôi và làm theo hướng dẫn tại đó. Thu thập càng nhiều thông tin càng tốt! + +## Báo cáo + +Chúng tôi theo dõi các vấn đề trên GitHub. Đảm bảo rằng bạn mở sự cố của mình trong [kho lưu trữ chính xác](https://github.com/flarum) và điền vào tất cả thông tin trong mẫu Báo cáo lỗi. + +Nếu bạn có thể, hãy kiểm tra xem sự cố có thể tái tạo được bằng phiên bản Flarum mới nhất hay không. Nếu bạn đang sử dụng phiên bản phát hành trước hoặc phiên bản phát triển, vui lòng cho biết phiên bản cụ thể mà bạn đang sử dụng. + +Hãy nhớ rằng: mục tiêu của báo cáo lỗi là giúp chúng tôi dễ dàng sao chép lỗi và sửa chữa nó. Bạn có thể muốn đọc [bài viết này](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html) để biết một số mẹo hữu ích về cách viết báo cáo lỗi hiệu quả. Nó **bắt buộc** bạn phải mô tả rõ ràng các bước cần thiết để tái tạo sự cố mà bạn đang gặp phải. Các vấn đề không có bước tái tạo rõ ràng sẽ không được xử lý. Nếu một vấn đề có nhãn "cần xác minh" không nhận được thêm thông tin nào từ tác giả của vấn đề trong hơn 5 ngày, nó sẽ bị đóng. + +Khi bạn đã đăng báo cáo của mình, chúng tôi đề nghị bạn *theo dõi cuộc thảo luận* và kiên nhẫn chờ đợi. Chúng tôi có thể cần hỏi thêm chi tiết hoặc làm rõ; nhưng chúng tôi luôn có nhiều việc phải làm và có thể mất một thời gian trước khi chúng tôi có thể cung cấp cho báo cáo của bạn thời gian xứng đáng. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md new file mode 100644 index 000000000..e13083f28 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md @@ -0,0 +1,51 @@ +# Quy tắc ứng xử + +### _Chào bạn đến với Cộng đồng Flarum!_ + +... Và cảm ơn vì đã tham gia cùng chúng tôi! Chúng tôi rất hào hứng với Flarum và luôn vui mừng gặp gỡ những người có cùng cảm nhận. Chúng tôi muốn *mọi người* tận dụng tối đa Flarum và cộng đồng Flarum, vì vậy chúng tôi yêu cầu bạn đọc và làm theo các nguyên tắc này. Những điều này áp dụng cho dù bạn đang sử dụng diễn đàn của chúng tôi, trò chuyện Discord, giao tiếp trên GitHub hoặc bất kỳ hình thức giao tiếp nào khác mà không có cộng đồng Flarum. + +### Trên tất cả, hãy trở nên tuyệt vời! + +Tất cả chúng ta ở đây để nói về Flarum và cùng nhau làm việc để biến nó trở thành một ứng dụng tốt hơn nữa. Phê bình các ý kiến ​​(tất nhiên bằng các lập luận hợp lý) là một phần quan trọng của điều đó. Nhưng đừng để bị cuốn trôi và lao vào các cuộc tấn công cá nhân, bởi vì sự tiêu cực chỉ cản đường. Chúng tôi yêu cầu bạn tránh những điều sau: + +- Ngôn ngữ xúc phạm hoặc lăng mạ, cũng như bất kỳ loại ngôn từ kích động thù địch nào +- Các bài đăng nhằm quấy rối, mạo danh hoặc bôi nhọ người khác +- Xóa nội dung đã đăng không cần thiết +- Cố gắng lạm dụng hoặc tiết lộ thông tin cá nhân của người khác +- Nội dung khiêu dâm hoặc khiêu dâm +- Thư rác, bài đăng lừa đảo và bất kỳ hành động nào nhằm làm xấu mặt trang web này +- Thảo luận về vi phạm bản quyền phần mềm và các chủ đề tương tự + +*Tất cả những điều trên là cơ sở để người kiểm duyệt hành động.* Nếu bạn gặp vấn đề với một thành viên khác, chúng tôi yêu cầu bạn không tự mình đối mặt với họ. Nếu là trên diễn đàn, vui lòng sử dụng lệnh *Báo cáo* trên bài đăng được đề cập, sau đó giao cho nhân viên xử lý tình huống. Otherwise, report the violation using our [contact page](https://flarum.org/foundation/contact), option Legal. + +Người kiểm duyệt của chúng tôi có thể chỉnh sửa hoặc xóa bất kỳ nội dung nào gây khó chịu hoặc làm gián đoạn luồng giao tiếp. Các hành vi vi phạm nghiêm trọng hoặc nhiều lần có thể dẫn đến việc tạm ngưng tài khoản của người dùng vi phạm. Vì vậy, bạn biết đấy, *hãy thật tuyệt*. 😎 + +### Hãy tự nghe + +Bạn muốn bắt đầu một cuộc thảo luận mới? Trước tiên, hãy nhớ đọc [Câu hỏi thường gặp của chúng tôi](faq.md) và nhấp vào các liên kết để đảm bảo bạn được thông báo đầy đủ về dự án. Sau đó, dành thời gian duyệt qua diễn đàn, tự làm quen với [hệ thống thẻ](https://discuss.flarum.org/tags) và thực hiện một vài tìm kiếm cho các từ khóa liên quan đến chủ đề của bạn: *có thể ai đó đã bắt đầu thảo luận về nó!* + +Khi bạn chắc chắn rằng mình đã sẵn sàng để bắt đầu một cuộc thảo luận, hãy ghi nhớ những điểm sau: + +- Đặt cho nó một tiêu đề tốt! Bạn sẽ nhận được kết quả tốt nhất nếu tiêu đề của bạn thể hiện rõ điều bạn muốn nói. +- Chọn (các) thẻ phù hợp. Điều này sẽ làm tăng khả năng bài viết của bạn sẽ được đọc và trả lời kịp thời. +- *Đừng* đăng nhiều lần về cùng một chủ đề, vì làm như vậy sẽ có tác dụng ngược lại. +- If not using a tag set aside for multilingual use, *post in English only.* We can't help you if we don't understand your posts. +- Hãy nhớ rằng, bạn không cần phải ký vào các bài viết của mình. Chúng tôi có hồ sơ của bạn để cho chúng tôi biết bạn là ai. + +Hãy cố gắng giúp chúng tôi giữ mọi thứ ngăn nắp. Thời gian dành cho việc thu dọn là thời gian mà chúng tôi không thể dành để tìm hiểu bạn, thảo luận các vấn đề của bạn và nói về Flarum. Và đó, sau tất cả, là những gì tất cả chúng ta ở đây để làm! + +### Thực hiện đếm câu trả lời của bạn + +Bạn đang dành thời gian để tham gia vào một cuộc thảo luận, với hy vọng rằng những người khác sẽ đọc ý tưởng của bạn và xem xét chúng. Vì vậy, tại sao không nỗ lực để làm cho câu trả lời của bạn đáng đọc? + +- Đừng trả lời một tiêu đề. Hãy dành chút thời gian để *đọc* OP và ít nhất *quét* phần còn lại của cuộc trò chuyện trước. +- Hãy tự hỏi bản thân xem câu trả lời của bạn có bổ sung vào cuộc thảo luận hay không. Nếu không, hãy suy nghĩ kỹ hơn trước khi đăng. +- Tránh đưa ra những bài viết dài một từ chỉ để đồng ý với ai đó; bạn có thể sử dụng nút "Thích" cho việc đó. +- Tránh tạo nhiều bài viết liên tiếp khi một bài đã đủ. Đây là một diễn đàn, không phải một phòng trò chuyện. +- Nếu câu trả lời của bạn có khả năng làm chuyển hướng tiến trình của cuộc thảo luận, thay vào đó, hãy cân nhắc bắt đầu một cuộc thảo luận mới. +- Thay vào đó, nếu bạn chỉ muốn đăng một chút vô nghĩa như một bài kiểm tra, vui lòng thực hiện việc đó trong thẻ [Test Posting](https://discuss.flarum.org/t/sandbox). +- Đảm bảo rằng câu trả lời của bạn cung cấp phản hồi và hỗ trợ mang tính xây dựng để tạo ra một cộng đồng hòa nhập. + +Sẽ không ai phàn nàn về những trò đùa không thường xuyên hoặc nhận xét thông minh. Chúng tôi muốn giữ cho tâm trạng nhẹ nhàng! Nhưng để giữ cho mọi thứ hiệu quả, chúng tôi yêu cầu bạn cố gắng tránh hoàn toàn việc thảo luận bị lệch. + +> Cảm ơn Dominion vì sự giúp đỡ của anh ấy trong việc đưa các nguyên tắc này lại với nhau. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/composer.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/composer.md new file mode 100644 index 000000000..c92ac175a --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/composer.md @@ -0,0 +1,152 @@ + +# Composer + +Flarum sử dụng một chương trình có tên là [Composer](https://getcomposer.org) để quản lý các phần phụ thuộc và tiện ích mở rộng của nó. Bạn sẽ cần sử dụng trình soạn nhạc nếu bạn muốn: + +- Install or update Flarum through the command line +- Install, update, or remove Flarum extensions through the command line + +Hướng dẫn này được cung cấp dưới dạng giải thích ngắn gọn về Composer. Chúng tôi thực sự khuyên bạn nên tham khảo [tài liệu chính thức](https://getcomposer.org/doc/00-intro.md) để biết thêm thông tin. + +:::tip Shared Hosting + +On shared hosting it is recommended to use the Extension Manager extension instead of Composer. It is a graphical interface for Composer that allows you to install, update and remove extensions without the need for SSH access. You can directly install Flarum using an archive file, without the need for Composer. With the extension manager pre-installed, check the [installation guide](install.md#installing-by-unpacking-an-archive) for more information. + +::: + +## Composer là gì? + +> Composer là một công cụ để quản lý sự phụ thuộc trong PHP. Nó cho phép bạn khai báo các thư viện mà dự án của bạn phụ thuộc vào và nó sẽ quản lý (cài đặt/cập nhật) chúng cho bạn. - [Giới thiệu Composer](https://getcomposer.org/doc/00-intro.md](https://getcomposer.org/doc/00-intro.md)) + +Mỗi cài đặt Flarum chủ yếu bao gồm lõi Flarum và một tập hợp các [tiện ích mở rộng](extensions.md). Mỗi cái trong số này có các phụ thuộc và bản phát hành riêng của nó. + +Trước đây, các khuôn khổ diễn đàn sẽ quản lý các tiện ích mở rộng bằng cách yêu cầu người dùng tải lên các tệp zip có mã tiện ích mở rộng. Điều đó có vẻ đơn giản, nhưng các vấn đề nhanh chóng trở nên rõ ràng: + +- Tải lên các tệp zip ngẫu nhiên từ internet có xu hướng là một ý tưởng tồi. Việc yêu cầu các tiện ích mở rộng được tải xuống từ một nguồn trung tâm như [ Packagist ](https://packagist.org/) khiến việc spam mã độc trở nên tẻ nhạt hơn và đảm bảo rằng mã nguồn có sẵn trên GitHub cho phần mở rộng miễn phí/công khai. +- Giả sử Tiện ích mở rộng A yêu cầu v4 của một số thư viện và Tiện ích mở rộng B yêu cầu v5 của cùng thư viện đó. Với giải pháp dựa trên zip, một trong hai phần phụ thuộc có thể ghi đè lên phần còn lại, gây ra tất cả các loại vấn đề không nhất quán. Hoặc cả hai sẽ cố gắng chạy cùng một lúc, điều này sẽ khiến PHP gặp sự cố (bạn không thể khai báo cùng một lớp hai lần). +- Các tệp zip có thể gây ra rất nhiều đau đầu nếu cố gắng tự động hóa việc triển khai, chạy các bài kiểm tra tự động hoặc mở rộng quy mô đến nhiều nút máy chủ. +- Không có cách nào tốt để đảm bảo rằng các phiên bản tiện ích mở rộng xung đột không thể được cài đặt hoặc phiên bản PHP hệ thống và các yêu cầu về tiện ích mở rộng được đáp ứng. +- Chắc chắn, chúng tôi có thể nâng cấp các tiện ích mở rộng bằng cách thay thế tệp zip. Nhưng nâng cấp lõi Flarum thì sao? Và làm thế nào chúng tôi có thể đảm bảo rằng các tiện ích mở rộng có thể khai báo phiên bản lõi nào mà chúng tương thích với? + +Composer xử lý tất cả những vấn đề này và hơn thế nữa! + +## Flarum và Composer + +Khi bạn vào [cài đặt Flarum](install.md#installing), bạn thực sự đang làm 2 điều: + +1. Tải xuống "bộ khung" bản soạn sẵn cho Flarum. Điều này bao gồm tệp `index.php` xử lý các yêu cầu web, tệp `flarum` cung cấp CLI và một loạt cấu hình máy chủ web và thiết lập thư mục. Điều này được lấy từ [`flarum/flarum` kho lưu trữ github](https://github.com/flarum/flarum) và không thực sự chứa bất kỳ mã nào cần thiết để Flarum chạy. +2. Cài đặt các gói `composer` cần thiết cho Flarum, cụ thể là lõi Flarum và một số phần mở rộng đi kèm. Chúng được gọi bởi các tệp `index.php` và `flarum` từ bước 1 và là phần triển khai của Flarum. Chúng được chỉ định trong tệp `composer.json` có trong khung. + +Khi bạn muốn cập nhật Flarum hoặc thêm/cập nhật/xóa phần mở rộng, bạn sẽ thực hiện việc này bằng cách chạy các lệnh `composer`. Mỗi lệnh là khác nhau, nhưng tất cả các lệnh đều tuân theo cùng một quy trình chung: + +1. Cập nhật tệp `composer.json` để thêm/xóa/cập nhật gói. +2. Thực hiện một loạt phép toán để có được phiên bản tương thích mới nhất của mọi thứ nếu có thể, hoặc tìm ra lý do tại sao việc sắp xếp được yêu cầu là không thể. +3. Nếu mọi thứ hoạt động, hãy tải xuống phiên bản mới của mọi thứ cần được cập nhật. Nếu không, hãy hoàn nguyên các thay đổi của `composer.json` + +Khi chạy các lệnh `composer.json`, hãy đảm bảo chú ý đến kết quả đầu ra. Nếu có lỗi, nó có thể sẽ cho bạn biết liệu đó có phải là do sự không tương thích của tiện ích mở rộng, phiên bản PHP không được hỗ trợ, thiếu các tiện ích mở rộng PHP hay do nguyên nhân khác. + +### Tệp `composer.json` + +Như đã đề cập ở trên, toàn bộ cấu hình trình soạn nhạc cho trang web Flarum của bạn được chứa bên trong tệp `composer.json`. Bạn có thể tham khảo [tài liệu về composer](https://getcomposer.org/doc/04-schema.md) để biết một giản đồ cụ thể, nhưng bây giờ, hãy xem qua một trình soạn nhạc `composer.json` từ `flarum/flarum`: + +```json +{ + // Phần sau đây chủ yếu chỉ là siêu dữ liệu về gói. + // Đối với quản trị viên diễn đàn, điều này không thực sự quan trọng. + "name": "flarum/flarum", + "description": "Delightfully simple forum software.", + "type": "project", + "keywords": [ + "forum", + "discussion" + ], + "homepage": "https://flarum.org/", + "license": "MIT", + "authors": [ + { + "name": "Flarum", + "email": "info@flarum.org", + "homepage": "https://flarum.org/team" + } + ], + "support": { + "issues": "https://github.com/flarum/core/issues", + "source": "https://github.com/flarum/flarum", + "docs": "https://flarum.org/docs/" + }, + // End of metadata + + // This next section is the one we care about the most. + // Đó là danh sách các gói chúng tôi muốn và các phiên bản cho mỗi gói. + // Chúng ta sẽ thảo luận về vấn đề này ngay sau đây. + "require": { + "flarum/core": "^1.0", + "flarum/approval": "*", + "flarum/bbcode": "*", + "flarum/emoji": "*", + "flarum/lang-english": "*", + "flarum/flags": "*", + "flarum/likes": "*", + "flarum/lock": "*", + "flarum/markdown": "*", + "flarum/mentions": "*", + "flarum/nicknames": "*", + "flarum/pusher": "*", + "flarum/statistics": "*", + "flarum/sticky": "*", + "flarum/subscriptions": "*", + "flarum/suspend": "*", + "flarum/tags": "*" + }, + + // Nhiều cấu hình composer khác nhau. Những cái ở đây là mặc định hợp lý. + // Xem https://getcomposer.org/doc/06-config.md để biết danh sách các tùy chọn. + "config": { + "preferred-install": "dist", + "sort-packages": true + }, + + // Nếu nhà soạn nhạc có thể tìm thấy phiên bản ổn định (không phải dev, alpha hoặc beta) + // của một gói, nó sẽ sử dụng cái đó. Nói chung, sản xuất + // các trang web không nên chạy phần mềm beta trừ khi bạn biết mình đang làm gì. + "prefer-stable": true +} +``` + +Hãy tập trung vào phần `request` đó. Mỗi mục nhập là tên của một gói composer và một chuỗi phiên bản. Để đọc thêm về chuỗi phiên bản, hãy xem [tài liệu về composer](https://semver.org/) có liên quan. + +Đối với các dự án Flarum, có một số loại mục nhập bạn sẽ thấy trong phần `require` của `flarum /core` cài đặt gốc của bạn: + +- Bạn PHẢI có mục nhập `flarum/core`. Điều này phải có một chuỗi phiên bản rõ ràng tương ứng với bản phát hành chính mà bạn muốn cài đặt. Đối với các phiên bản Flarum 1.x, đây sẽ là `^1.0`. +- Bạn sẽ có một mục nhập cho mỗi tiện ích mở rộng mà bạn đã cài đặt. Một số tiện ích mở rộng đi kèm được bao gồm theo mặc định (ví dụ: `flarum/tags`, `flarum/pause`, v.v.), [những tiện ích khác mà bạn sẽ thêm qua lệnh của composer](extensions.md). Trừ khi bạn có lý do để làm khác (ví dụ: bạn đang thử nghiệm phiên bản beta của một gói), chúng tôi khuyên bạn nên sử dụng dấu hoa thị làm chuỗi phiên bản cho các tiện ích mở rộng (`*`). Điều này có nghĩa là "cài đặt phiên bản mới nhất tương thích với flarum/core của tôi". +- Một số tiện ích mở rộng / tính năng có thể yêu cầu các gói PHP không phải là tiện ích mở rộng Flarum. Ví dụ: bạn cần thư viện guzzle để sử dụng [trình điều khiển thư Mailgun](mail.md). Trong những trường hợp này, hướng dẫn cho tiện ích mở rộng/tính năng được đề cập phải giải thích chuỗi phiên bản nào được sử dụng. + +## Làm thế nào để cài đặt Composer? + +Như với bất kỳ phần mềm nào khác, Composer trước tiên phải được [cài đặt](https://getcomposer.org/download/) trên máy chủ nơi Flarum đang chạy. Có một số tùy chọn tùy thuộc vào loại lưu trữ web bạn có. + +### Máy chủ web chuyên dụng + +Trong trường hợp này, bạn có thể cài đặt composer theo khuyến nghị trong [hướng dẫn](https://getcomposer.org/doc/00-intro.md#system-requirements) Composer. + +### Managed / Shared hosting + +Nếu Composer chưa được cài đặt sẵn (bạn có thể kiểm tra điều này bằng cách chạy `composer --version`), bạn có thể sử dụng [hướng dẫn sử dụng cài đặt](https://getcomposer.org/composer-stable.phar). Chỉ cần tải composer.phar lên thư mục của bạn và chạy `/path/to/your/php7 composer.phar COMMAND` cho bất kỳ lệnh nào được ghi dưới dạng `composer COMMAND`. + +:::danger + +Một số bài báo trên internet sẽ đề cập rằng bạn có thể sử dụng các công cụ như PHP shell. Nếu bạn không chắc mình đang làm gì hoặc họ đang nói về điều gì - hãy cẩn thận! Trình bao web không được bảo vệ là **cực kỳ** nguy hiểm. + +::: + +## Cách sử dụng Composer? + +Bạn sẽ cần sử dụng Composer trên **C**ommand-**l**ine **i**nterface (CLI). Đảm bảo bạn có thể truy cập máy chủ của mình qua **S**ecure**Sh**ell (SSH). + +Sau khi bạn đã cài đặt Composer, bạn sẽ có thể chạy các lệnh Composer trong thiết bị đầu cuối SSH của mình thông qua `composer COMMAND`. + +:::info Tối ưu hoá + +Sau hầu hết các lệnh, bạn sẽ muốn chạy `composer dump-autoload -a`. Về cơ bản, điều này lưu trữ các tệp PHP để chúng chạy nhanh hơn. + +::: diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/config.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/config.md new file mode 100644 index 000000000..42526a750 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/config.md @@ -0,0 +1,35 @@ +# Tệp cấu hình + +Chỉ có một số nơi không thể cấu hình thông qua bảng điều khiển quản trị Flarum (không bao gồm database), đó chính là tệp `config.php` nằm trong thư mục càid dặt Flarum của bạn. + +Tệp này mặc dù rất nhẹ, nhưng nó chứa các thông tin quan trọng để Flarum của bạn hoạt động. + +Nếu tệp tồn tại, điều đó cho biết rằng Flarum đã được cài đặt. Nó cũng cung cấp cho Flarum với thông tin database và nhiều hơn nữa. + +Dưới đây là tổng quan nhanh về những thứ có trong tệp cấu hình: + +```php + false, // bật tắt chế độ gỡ lỗi, sử dụng để khắc phục sự cố + 'offline' => false, // bật tắt chế độ bảo trì. Quản trị viên và người dùng sẽ không thể truy cập vào trang web. + 'database' => + array ( + 'driver' => 'mysql', // trình điều khiển cơ sở dữ liệu. Vd: MySQL, MariaDB... + 'host' => 'localhost', // máy chủ kết nối, localhost trong hầu hết các trường hợp trừ khi sử dụng dịch vụ bên ngoài + 'database' => 'flarum', // tên cơ sở dữ liệu + 'username' => 'root', // tên người dùng cơ sở dữ liệu + 'password' => '', // mật khẩu cơ sở dữ liệu + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', // tiền tố cho các bảng, hữu ích nếu bạn đang chia sẻ cùng một cơ sở dữ liệu với một dịch vụ khác + 'port' => '3306', // cổng kết nối, mặc định là 3306 với MySQL + 'strict' => false, + ), + 'url' => 'https://flarum.localhost', // URL trang web, bạn sẽ muốn thay đổi điều này nếu bạn thay đổi tên miền + 'paths' => + array ( + 'api' => 'api', // /api chuyển đến API + 'admin' => 'admin', // /admin chuyển tới quản trị viên + ), +); +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/console.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/console.md new file mode 100644 index 000000000..e1f38674d --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/console.md @@ -0,0 +1,77 @@ +# Console + +Ngoài bảng điều khiển quản trị, Flarum cung cấp một số lệnh console để giúp quản lý diễn đàn của bạn qua thiết bị đầu cuối + +Using the console: + +1. `ssh` vào máy chủ nơi lưu trữ cài đặt flarum của bạn +2. `cd` to the folder that contains the file `flarum` +3. Chạy lệnh `php flarum [command]` + +## Lệnh mặc định + +### list + +Liệt kê tất cả các lệnh quản lý có sẵn, cũng như hướng dẫn sử dụng các lệnh quản lý + +### help + +`php flarum help [tên_câu_lệnh]` + +Hiển thị kết quả trợ giúp cho một lệnh nhất định. + +Bạn cũng có thể xuất ra trợ giúp ở các định dạng khác bằng cách sử dụng tùy chọn `--format`: + +`php flarum help --format=xml list` + +Để hiển thị danh sách các lệnh có sẵn, vui lòng sử dụng lệnh danh sách. + +### info + +`php flarum info` + +Get information about Flarum's core and installed extensions. Điều này rất hữu ích cho các sự cố gỡ lỗi và nên được chia sẻ khi yêu cầu hỗ trợ. + +### cache:clear + +`php flarum cache:clear` + +Xóa bộ đệm ẩn phụ trợ, bao gồm js/css đã tạo, bộ đệm định dạng văn bản và các bản dịch đã lưu trong bộ đệm. Thao tác này sẽ được chạy sau khi cài đặt hoặc gỡ bỏ các tiện ích mở rộng và việc chạy này phải là bước đầu tiên khi sự cố xảy ra. + +### assets:publish + +`php flarum assets:publish` + +Xuất bản nội dung từ lõi và tiện ích mở rộng (ví dụ: JS/CSS đã biên dịch, biểu tượng bootstrap, biểu trưng, ​​v.v.). Điều này hữu ích nếu nội dung của bạn bị hỏng hoặc nếu bạn đã chuyển đổi [trình điều khiển hệ thống tệp](extend/filesystem.md) cho đĩa `flarum-asset`. + +### migrate + +`php flarum migrate` + +Chạy tất cả các lần di chuyển chưa thực hiện. Điều này sẽ được sử dụng khi một tiện ích mở rộng sửa đổi cơ sở dữ liệu được thêm vào hoặc cập nhật. + +### migrate:reset + +`php flarum migrate:reset --extension [extension_id]` + +Đặt lại tất cả các lần di chuyển cho một tiện ích mở rộng. Điều này hầu hết được sử dụng bởi các nhà phát triển tiện ích mở rộng, nhưng đôi khi, bạn có thể cần phải chạy điều này nếu bạn đang xóa một tiện ích mở rộng và muốn xóa tất cả dữ liệu của nó khỏi cơ sở dữ liệu. Xin lưu ý rằng tiện ích mở rộng được đề cập hiện phải được cài đặt (nhưng không nhất thiết phải được bật) để tiện ích này hoạt động. + +### schedule:run + +`php flarum schedule:run` + +Nhiều tiện ích mở rộng sử dụng các công việc đã lên lịch để chạy các tác vụ theo chu kỳ. Điều này có thể bao gồm dọn dẹp cơ sở dữ liệu, đăng bản nháp đã lên lịch, tạo sơ đồ trang, v.v. Nếu bất kỳ tiện ích mở rộng nào của bạn sử dụng công việc đã lên lịch, bạn nên thêm một [công việc cron](https://ostechnix.com/a-beginners-guide-to-cron-jobs/) để chạy lệnh này trên một khoảng thời gian đều đặn: + +``` +* * * * * cd /path-to-your-flarum-install && php flarum schedule:run >> /dev/null 2>&1 +``` + +Nói chung không nên chạy lệnh này theo cách thủ công. + +Lưu ý rằng một số máy chủ không cho phép bạn chỉnh sửa cấu hình cron trực tiếp. Trong trường hợp này, bạn nên tham khảo ý kiến ​​chủ nhà của mình để biết thêm thông tin về cách lên lịch công việc cho cron. + +### schedule:list + +`php flarum schedule:list` + +Lệnh này trả về danh sách các lệnh được lập lịch (xem `schedule:run` để biết thêm thông tin). Điều này hữu ích để xác nhận rằng các lệnh do tiện ích mở rộng của bạn cung cấp đã được đăng ký đúng cách. **Điều này không thể** kiểm tra xem các công việc cron đã được lên lịch thành công hay đang được chạy. \ No newline at end of file diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md new file mode 100644 index 000000000..3c17433f0 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md @@ -0,0 +1,26 @@ +# Tài liệu và Bản dịch + +## Thêm tài liệu + +Thêm tài liệu có thể giúp vô số người dùng Flarum trong tương lai. Một vài ý tưởng về những việc cần làm: + +- Hướng dẫn sử dụng để giúp người dùng Flarum với một số tính năng nâng cao của Flarum. +- [Đặt câu hỏi](faq.md). +- Các bước [khắc phục sự cố](troubleshoot.md) mở rộng. +- Hướng dẫn từng bước để phát triển hoặc cài đặt Flarum. +- [Hướng dẫn tham khảo kỹ thuật](extend/README.md) dành cho lập trình viên tiện ích mở rộng. +- Cải thiện theo nghĩa đen bất kỳ thứ gì khác mà bạn nghĩ chúng tôi nên giải thích kỹ hơn hoặc giải thích rõ hơn. + +Một cách tốt để tìm chủ đề để viết là tìm các câu hỏi phổ biến trong [thẻ hỗ trợ](https://discuss.flarum.org/t/support) của cộng đồng chúng tôi. + +## Dịch Flarum + +Chúng tôi muốn Flarum có thể truy cập được cho tất cả mọi người, bất kể ngôn ngữ! Bằng cách đóng góp các bản dịch, bạn có thể giúp nhiều người khác thưởng thức Flarum. Hơn hết, chúng tôi sử dụng GUI thân thiện với người dùng cho các bản dịch, vì vậy không cần kỹ năng kỹ thuật nào để trợ giúp! + +Bản dịch cho cốt lõi Flarum, tiện ích mở rộng đi kèm và tiện ích mở rộng cộng đồng được quản lý thông qua [Weblate](https://weblate.rob006.net/projects/flarum/). + +Các bản dịch cho tài liệu này được quản lý thông qua [Crowdin](https://crowdin.com/project/flarum-docs). + +Flarum Foundation đã thành lập tổ chức "flarum-lang" để hỗ trợ các biên dịch viên và đảm bảo tính khả dụng liên tục của các gói ngôn ngữ. Bạn có thể tìm hiểu thêm về điều này bằng cách [truy cập kho lưu trữ GitHub](https://github.com/flarum-lang/about). + +Nếu bạn muốn hỗ trợ gói ngôn ngữ hiện có, bắt đầu bản dịch mới hoặc bạn gặp sự cố khi sử dụng weblate hoặc crowdin, tốt nhất hãy [liên hệ với nhóm flarum-lang](https://discuss.flarum.org/d/27519-the-flarum-language-project). diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/contributing.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/contributing.md new file mode 100644 index 000000000..461308b11 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/contributing.md @@ -0,0 +1,170 @@ +# Giúp xây dựng Flarum + +Bạn quan tâm đến việc đóng góp vào sự phát triển của Flarum? Thật tuyệt! Từ [mở báo cáo lỗi](bugs.md) đến tạo yêu cầu kéo: mọi yêu cầu đơn lẻ đều được đánh giá cao và hoan nghênh. Flarum sẽ không thể thực hiện được nếu không có sự đóng góp của cộng đồng. + +Trước khi đóng góp, vui lòng đọc [quy tắc ứng xử](code-of-conduct.md). + +Tài liệu này là hướng dẫn cho các nhà phát triển muốn đóng góp mã cho Flarum. Nếu bạn mới bắt đầu, chúng tôi khuyên bạn nên đọc tài liệu [Bắt đầu](/extend/start.md) trong tài liệu Tiện ích mở rộng để hiểu thêm một chút về cách hoạt động của Flarum. + +## Tại sao lại đóng góp Flarum? + +⚡ **Có tác động thực sự.** Có hàng nghìn phiên bản Flarum, với hàng triệu người dùng cuối tổng hợp. Bằng cách đóng góp cho Flarum, mã của bạn sẽ có tác động tích cực đến tất cả chúng. + +🔮 **Định hình tương lai của Flarum.** Chúng tôi có một công việc tồn đọng dài và thời gian có hạn. Nếu bạn sẵn sàng ủng hộ một tính năng hoặc thay đổi, thì điều đó có nhiều khả năng xảy ra hơn và bạn sẽ có thể đưa ra tầm nhìn của mình cho nó. Ngoài ra, lộ trình và các mốc quan trọng của chúng tôi do [nhóm phát triển cốt lõi](https://flarum.org/team) của chúng tôi đặt ra và tất cả chúng tôi đều bắt đầu với tư cách là cộng tác viên. Con đường tốt nhất để tạo ảnh hưởng là đóng góp. + +🧑‍💻 **Trở thành Kỹ sư giỏi hơn.** Cơ sở mã của chúng tôi hiện đại và chúng tôi đánh giá cao kỹ thuật tốt và mã sạch. Ngoài ra còn có rất nhiều vấn đề thú vị, đầy thách thức cần giải quyết liên quan đến thiết kế, cơ sở hạ tầng, hiệu suất và khả năng mở rộng. Đặc biệt nếu bạn là sinh viên hoặc mới bắt đầu sự nghiệp, làm việc trên Flarum là một cơ hội tuyệt vời để xây dựng các kỹ năng phát triển. + +🎠 **Thật thú vị!** Chúng tôi thực sự thích làm việc trên Flarum: có rất nhiều thử thách thú vị và các tính năng thú vị để xây dựng. Chúng tôi cũng có một cộng đồng tích cực trên [diễn đàn của chúng tôi](https://discuss.flarum.org) và [máy chủ Discord](https://flarum.org/chat). + +## Những gì cần làm + +Hãy xem [Các mốc quan trọng](https://github.com/flarum/core/milestones) sắp tới của chúng tôi để biết tổng quan về những việc cần phải làm. Xem nhãn [Vấn đề đầu tiên tốt nhất](https://github.com/flarum/core/labels/Good%20first%20issue) để biết danh sách các vấn đề tương đối dễ bắt đầu. Nếu có bất cứ điều gì bạn không chắc chắn, đừng ngần ngại hỏi! Tất cả chúng tôi chỉ mới bắt đầu một lần. + +Nếu bạn đang lên kế hoạch tiếp tục làm việc gì đó, vui lòng nhận xét về vấn đề có liên quan hoặc tạo một vấn đề mới trước. Bằng cách này, chúng tôi có thể đảm bảo rằng công việc quý giá của bạn không trở nên vô ích. + +Vì Flarum hướng đến tiện ích mở rộng, chúng tôi thực sự khuyên bạn nên sử dụng [tài liệu về tiện ích mở rộng của chúng tôi](extend/README.md) để làm tài liệu tham khảo khi làm việc trên lõi, cũng như đối với các tiện ích mở rộng đi kèm. Bạn nên bắt đầu với [phần giới thiệu](extend/README.md) để hiểu rõ hơn về triết lý mở rộng của chúng tôi. + +## Thiết lập môi trường + +### Thiết lập Codebase cục bộ + +[flarum/flarum](https://github.com/flarum/flarum) là một ứng dụng "skeleton" sử dụng Composer để tải xuống gói cốt lõi và một loạt các phần mở rộng. Mã nguồn cho Flarum cốt lõi, phần mở rộng và tất cả các gói được sử dụng bởi phần nói trên nằm trong Flarum monorepo [flarum/framework](https://github.com/flarum/framework). Để đóng góp vào những điều này, bạn sẽ cần phải phân nhánh và sao chép cục bộ kho lưu trữ monorepo, sau đó thêm nó vào môi trường phát triển của bạn dưới dạng [đường dẫn kho lưu trữ Composer](https://getcomposer.org/doc/05-repositories.md#path): + +```bash +git clone https://github.com/flarum/flarum.git +cd flarum + +# Or, when you want to clone directly into the current directory +git clone https://github.com/flarum/flarum.git . +# Note, the directory must be empty + +# Set up a Composer path repository for Flarum monorepo packages +composer config repositories.0 path "PATH_TO_MONOREPO/*/*" +git clone https://github.com//framework.git PATH_TO_MONOREPO +``` + +Tiếp theo, hãy đảm bảo rằng Composer chấp nhận các bản phát hành không ổn định từ các bản sao cục bộ của bạn bằng cách đặt khóa `minimum-stability` thành `dev` trong `composer.json`. + +Cuối cùng, chạy `composer install` để hoàn tất cài đặt từ kho đường dẫn. + +Sau khi cài đặt cục bộ của bạn được thiết lập, hãy đảm bảo rằng bạn đã bật chế độ `debug` trong **config.php** và đặt `display_errors` thành `On` trong cấu hình php của bạn. Điều này sẽ cho phép bạn xem chi tiết lỗi cho cả Flarum và PHP. Chế độ gỡ lỗi cũng buộc biên dịch lại các tệp nội dung của Flarum theo từng yêu cầu, loại bỏ nhu cầu gọi `php flarum cache: clear` sau mỗi lần thay đổi đối với JavaScript hoặc CSS của tiện ích mở rộng. + +Mã front-end của Flarum được viết bằng ES6 và được chuyển sang JavaScript. Trong quá trình phát triển, bạn sẽ cần phải biên dịch lại JavaScript bằng cách sử dụng [Node.js](https://nodejs.org/) và [`yarn`](https://yarnpkg.com/). **Vui lòng không gửi các tệp `dist` khi gửi PR**; điều này sẽ tự động được xử lý khi các thay đổi được hợp nhất vào nhánh `main`. + +Để đóng góp cho giao diện người dùng, trước tiên hãy cài đặt các phụ thuộc JavaScript. Monorepo sử dụng [không gian làm việc của yarn](https://classic.yarnpkg.com/lang/en/docs/workspaces/) để dễ dàng cài đặt các phần phụ thuộc JS trên tất cả các gói bên trong. + +```bash +cd packages/framework +yarn install +``` + +Sau đó, bạn có thể xem các tệp JavaScript để biết các thay đổi trong quá trình phát triển: + +```bash +cd framework/core/js +yarn dev +``` + +Quá trình này cũng giống như các phần mở rộng. + +```bash +cd extensions/tags/js +yarn dev +``` + +### Công cụ phát triển + +Sau khi bạn đã tách và nhân bản các kho lưu trữ mà bạn sẽ làm việc, bạn sẽ cần thiết lập lưu trữ cục bộ để có thể kiểm tra các thay đổi của mình. Flarum hiện không đi kèm với máy chủ phát triển, vì vậy bạn sẽ cần thiết lập Apache/NGINX/Caddy/etc để chạy cài đặt Flarum cục bộ này. + +Ngoài ra, bạn có thể sử dụng các công cụ như, [Laravel Valet](https://laravel.com/docs/master/valet) (Mac), [XAMPP](https://www.apachefriends.org/index.html) (Windows), hoặc [Docker-Flarum](https://github.com/mondediefr/docker-flarum) (Linux) để làm máy chủ diễn đàn cục bộ. + +Hầu hết những người đóng góp cho Flarum đều phát triển với [PHPStorm](https://www.jetbrains.com/phpstorm/download/) hoặc [Visual Studio Code](https://code.visualstudio.com/). + +## Quy trình phát triển + +Quy trình đóng góp điển hình trông giống như sau: + +0. 🧭 **Lập kế hoạch** đóng góp của bạn + * Tìm ra [vấn đề bạn muốn giải quyết](#what-to-work-on) + * Thiết lập một [môi trường phát triển](#setting-up-a-local-codebase) + +1. 🌳 **Branch** tách branch thích hợp thành một branch tính năng mới. + * *Bug fixes* nên được gửi đến branch ổn định mới nhất. + * *Minor* các tính năng hoàn toàn tương thích ngược với bản phát hành Flarum hiện tại có thể được gửi đến nhánh ổn định mới nhất. + * *Major* các tính năng phải luôn được gửi đến nhánh `main`, chứa bản phát hành Flarum sắp tới. + * Nội bộ chúng tôi sử dụng lược đồ đặt tên `/` (ví dụ: `tz/refactor-frontend`). + +2. 🔨 **Viết** code. + * Xem bên dưới về [Kiểu coding](#coding-style). + +3. 🚦 **Thử nghiệm** code của bạn. + * Thêm các bài kiểm tra đơn vị khi cần thiết khi sửa lỗi hoặc thêm tính năng. + * Chạy bộ thử nghiệm với `vendor/bin/phpunit` trong thư mục gói có liên quan. + * Xem [ở đây](extend/testing.md) để biết thêm thông tin về thử nghiệm trong Flarum. + +4. 💾 **Commit** code của bạn với một thông điệp mô tả. + * Nếu thay đổi của bạn giải quyết được sự cố hiện có (thông thường, nó phải) bao gồm "Bản sửa lỗi số 123" trên một dòng mới, trong đó 123 là số sự cố. + * Thực hiện theo đặc tả của [Commits thông thường](https://www.conventionalcommits.org/en/v1.0.0/#summary). + * *Fix* cam kết phải mô tả vấn đề đã được khắc phục chứ không phải cách nó được khắc phục. + +5. 🎁 **Gửi** một Pull Request trên GitHub. + * Điền vào mẫu pull request. + * Nếu thay đổi của bạn là trực quan, hãy bao gồm ảnh chụp màn hình hoặc GIF thể hiện thay đổi. + * KHÔNG đăng ký các tệp JavaScript `dist`. Chúng sẽ được biên dịch tự động khi hợp nhất. + +6. 🤝 **Đính hôn** với nhóm Flarum để được chấp thuận. + * Các thành viên trong nhóm sẽ xem xét mã của bạn. Chúng tôi có thể đề xuất một số thay đổi hoặc cải tiến hoặc lựa chọn thay thế, nhưng đối với những thay đổi nhỏ, yêu cầu kéo của bạn sẽ nhanh chóng được chấp nhận. + * Khi giải quyết phản hồi, hãy đẩy các commit bổ sung thay vì ghi đè hoặc cắt bỏ (chúng tôi sẽ xóa khi hợp nhất). + +7. 🕺 **Nhảy** giống như bạn vừa đóng góp cho Flarum. + +## Kiểu coding + +Để giữ cho cơ sở mã Flarum sạch sẽ và nhất quán, chúng tôi có một số nguyên tắc về kiểu mã hóa mà chúng tôi tuân theo. Khi nghi ngờ, hãy đọc mã nguồn. + +Đừng lo lắng nếu kiểu mã của bạn không hoàn hảo! StyleCI và Prettier sẽ tự động kiểm tra định dạng cho mọi yêu cầu kéo. Điều này cho phép chúng tôi tập trung vào nội dung của đóng góp, không phải kiểu mã. + +### PHP + +Flarum tuân theo [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) tiêu chuẩn mã hóa và tiêu chuẩn tự động tải [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md). Trên hết, chúng tôi tuân thủ một số [các quy tắc kiểu khác](https://github.com/flarum/framework/blob/main/.styleci.yml). Chúng tôi sử dụng gợi ý loại PHP 7 và khai báo loại trả về nếu có thể và [PHPDoc](https://docs.phpdoc.org/) để cung cấp tài liệu nội tuyến. Hãy thử và bắt chước kiểu được sử dụng bởi phần còn lại của cơ sở mã trong các đóng góp của bạn. + +* Namespaces phải là số ít (ví dụ: `Flarum\Discussion`, không phải `Flarum\Discussions`) +* Interfaces phải được gắn với `Interface` (ví dụ: `MailableInterface`) +* Class Abstract phải được bắt đầu bằng `Abstract` (ví dụ: `AbstractModel`) +* Traits phải được gắn với `Trait` (ví dụ: `ScopeVisibilityTrait`) + +### JavaScript + +JavaScript của Flarum chủ yếu tuân theo [Hướng dẫn tạo kiểu Airbnb](https://github.com/airbnb/javascript). Chúng tôi sử dụng [ESDoc](https://esdoc.org/manual/tags.html) để cung cấp tài liệu nội tuyến. + +### Cơ sở dữ liệu + +**Cột** nên được đặt tên theo kiểu dữ liệu: +* DATETIME hoặc TIMESTAMP: `{verbed}_at` (ví dụ: created_at, read_at) hoặc `{verbed}_until` (ví dụ: suspended_until) +* INT là một số: `{noun}_count` (ví dụ: comment_count, word_count) +* Khoá ngoại: `{verbed}_{entity}_id` (ví dụ: hidden_user_id) + * Có thể bỏ qua động từ cho quan hệ chính (ví dụ: người đăng bài viết là `user_id`) +* BOOL: `is_{adjective}` (ví dụ: is_locked) + +**Bảng** phải được đặt tên như sau: +* Sử dụng dạng số nhiều (`discussions`) +* Phân tách nhiều từ bằng dấu gạch dưới (`access_tokens`) +* Đối với bảng mối quan hệ, hãy nối hai tên bảng ở dạng số ít với dấu gạch dưới theo thứ tự bảng chữ cái (ví dụ: `discussion_user`) + +### CSS + +Các lớp CSS của Flarum gần như tuân theo [THÍCH hợp quy ước đặt tên CSS](https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md) bằng cách sử dụng định dạng `.ComponentName-subsentName-modifierName`. + +### Bản dịch + +Chúng tôi sử dụng [định dạng khóa chuẩn](/extend/i18n.md#append-a-standard-key-format) để đặt tên các khóa dịch một cách mô tả và nhất quán. + +## Thỏa thuận cấp phép cộng tác viên + +Bằng cách đóng góp mã của bạn cho Flarum, bạn cấp cho Flarum Foundation (Stichting Flarum) một giấy phép không độc quyền, không thể thu hồi, trên toàn thế giới, miễn phí bản quyền, có thể cấp phép lại, có thể chuyển nhượng theo tất cả các quyền sở hữu trí tuệ liên quan của bạn (bao gồm bản quyền, bằng sáng chế và bất kỳ quyền nào khác), để sử dụng, sao chép, chuẩn bị các sản phẩm phái sinh của, phân phối và trình diễn công khai và hiển thị các Đóng góp theo bất kỳ điều khoản cấp phép nào, bao gồm nhưng không giới hạn: (a) giấy phép nguồn mở như giấy phép MIT; và (b) giấy phép nhị phân, độc quyền hoặc thương mại. Ngoại trừ các giấy phép được cấp ở đây, Bạn bảo lưu mọi quyền, quyền sở hữu và lợi ích đối với và đối với Khoản đóng góp. + +Bạn xác nhận rằng bạn có thể cấp cho chúng tôi những quyền này. Bạn tuyên bố rằng Bạn có quyền hợp pháp để cấp giấy phép trên. Nếu chủ lao động của Bạn có quyền đối với tài sản trí tuệ mà Bạn tạo ra, Bạn tuyên bố rằng Bạn đã nhận được sự cho phép để thực hiện các Đóng góp thay mặt cho chủ lao động đó, hoặc chủ nhân của Bạn đã từ bỏ các quyền đó đối với các Đóng góp đó. + +Bạn tuyên bố rằng các Đóng góp là tác phẩm gốc của bạn về quyền tác giả và theo hiểu biết của Bạn, không có người nào khác yêu cầu hoặc có quyền yêu cầu, bất kỳ quyền nào trong bất kỳ phát minh hoặc bằng sáng chế nào liên quan đến các Đóng góp. Bạn cũng tuyên bố rằng Bạn không có nghĩa vụ pháp lý, cho dù bằng cách ký kết thỏa thuận hay bằng cách khác, theo bất kỳ cách nào xung đột với các điều khoản của giấy phép này. + +Tổ chức Flarum thừa nhận rằng, ngoại trừ được mô tả rõ ràng trong Thỏa thuận này, bất kỳ Đóng góp nào mà bạn cung cấp đều dựa trên CƠ SỞ "NGUYÊN TRẠNG", KHÔNG CÓ ĐẢM BẢO HOẶC ĐIỀU KIỆN NÀO, BẤT KỲ LOẠI NÀO, RÕ RÀNG HOẶC NGỤ Ý, BAO GỒM, KHÔNG GIỚI HẠN, BẤT KỲ BẢO ĐẢM HOẶC ĐIỀU KIỆN NÀO TIÊU ĐỀ, KHÔNG VI PHẠM, KHẢ NĂNG LẠNH, HOẶC PHÙ HỢP VỚI MỤC ĐÍCH CỤ THỂ. \ No newline at end of file diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/README.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/README.md new file mode 100644 index 000000000..6b1c0c486 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/README.md @@ -0,0 +1,40 @@ +- - - +slug: '/extend' +- - - + +# Mở rộng Flarum + +Flarum là tối giản, nhưng nó cũng có khả năng mở rộng cao. Trên thực tế, hầu hết các tính năng đi kèm với Flarum thực sự là phần mở rộng! + +Cách tiếp cận này làm cho Flarum có thể tùy biến cực kỳ tốt. Người dùng có thể tắt bất kỳ tính năng nào mà họ không sử dụng trên diễn đàn và cài đặt các tiện ích mở rộng khác để tạo diễn đàn hoàn hảo cho cộng đồng của họ. + +Để đạt được khả năng mở rộng này, Flarum đã được xây dựng với các API và điểm mở rộng phong phú. Với một số kiến thức lập trình, bạn có thể tận dụng các API này để thêm bất kỳ tính năng nào bạn muốn. Phần này của tài liệu nhằm mục đích hướng dẫn bạn cách hoạt động của Flarum và cách sử dụng các API để bạn có thể tạo các tiện ích mở rộng của riêng mình. + +## Lõi với Tiện ích mở rộng + +Chúng ta vẽ ranh giới giữa Flarum cốt lõi và các phần mở rộng của nó ở đâu? Tại sao một số tính năng được bao gồm trong lõi, còn những tính năng khác thì không? Điều quan trọng là phải hiểu sự khác biệt này để chúng tôi có thể duy trì tính nhất quán và chất lượng trong hệ sinh thái của Flarum. + +**Flarum cốt lõi** không nhằm mục đích có đầy đủ các tính năng. Thay vào đó, nó là một giàn giáo, hoặc một khuôn khổ, cung cấp một nền tảng đáng tin cậy để các tiện ích mở rộng có thể xây dựng. Nó chỉ chứa chức năng cơ bản, chưa được tích hợp, cần thiết cho một diễn đàn: thảo luận, bài đăng, người dùng, nhóm và thông báo. + +**Tiện ích mở rộng đi kèm** là các tính năng được đóng gói cùng với Flarum và được bật theo mặc định. Chúng là các tiện ích mở rộng giống như bất kỳ tiện ích mở rộng nào khác và có thể bị vô hiệu hóa và gỡ cài đặt. Mặc dù phạm vi của chúng không nhằm giải quyết tất cả các trường hợp sử dụng, nhưng ý tưởng là làm cho chúng trở nên chung chung và đủ cấu hình để chúng có thể đáp ứng số đông. + +**Tiện ích mở rộng của bên thứ ba** là các tính năng do những người khác tạo ra và không được nhóm Flarum hỗ trợ chính thức. Chúng có thể được xây dựng và sử dụng để giải quyết các trường hợp sử dụng cụ thể hơn. + +Nếu bạn đang muốn giải quyết một lỗi hoặc thiếu sót của lõi hoặc của tiện ích mở rộng đi kèm hiện có, thì việc *đóng góp cho dự án tương ứng* có thể phù hợp hơn là phân tán nỗ lực vào tiện ích mở rộng mới của bên thứ ba. Bạn nên bắt đầu một cuộc thảo luận trên [Cộng đồng Flarum](https://discuss.flarum.org/) để có được góc nhìn của các nhà phát triển Flarum. + +## Tài nguyên hữu ích + +- [Tài liệu](start.md) +- [Mẹo dành cho nhà phát triển mới bắt đầu](https://discuss.flarum.org/d/5512-extension-development-tips) +- [Flarum CLI](https://github.com/flarum/cli) +- [Các lập trình viên giải thích về quá trình phát triển tiện ích mở rộng](https://discuss.flarum.org/d/6320-extension-developers-show-us-your-workflow) +- [Mẹo namespace tiện ích mở rộng](https://discuss.flarum.org/d/9625-flarum-extension-namespacing-tips) +- [Tài liệu Mithril js](https://mithril.js.org/) +- [Tài liệu API Laravel](https://laravel.com/api/8.x/) +- [Tài liệu API Flarum](https://api.flarum.org) +- [ES6 cheatsheet](https://github.com/DrkSephy/es6-cheatsheet) + +### Tìm sự giúp đỡ + +- [Cộng đồng Dev Flarum](https://discuss.flarum.org/t/dev) +- [Tham gia #extend trên discord](https://flarum.org/discord/) diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/admin.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/admin.md new file mode 100644 index 000000000..00f5984b7 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/admin.md @@ -0,0 +1,214 @@ +# Trang quản trị + +Beta 15 với trang quản trị và API giao diện người dùng được thiết kế mới. Bây giờ có thể dễ dàng thêm thiết lập hoặc quyền vào tiện ích mở rộng của bạn. + +Trước beta 15, thiết lập tiện ích mở rộng đã được thêm vào `SettingModal` hoặc họ đã thêm vào một trang mới để phức tạp việc thiết lập hơn. Bây giờ toàn bộ tiện ích mở rộng đã có trang chứa thông tin, thiết lập và quyền của tiện ích mở rộng cho riêng mình. + +Bạn có thể chỉ cần đăng ký cài đặt, mở rộng [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) cơ sở hoặc cung cấp trang hoàn toàn tùy chỉnh của riêng bạn. + +## API dữ liệu tiện ích mở rộng + +Đây là API mới cho phép bạn thêm settings vào tiện ích mở rộng chỉ với vài dòng mã. + +### Nói với API về tiện ích mở rộng của bạn + +Trước khi đăng ký setting nào đó, bạn cần cho `ExtensionData` hiểu rằng nó lấy dữ liệu cho tiện ích mở rộng nào. + +Chỉ cần thêm hàm `for` vào sau `app.extensionData` và truyền id tiện ích mở rộng của bạn vào. Để tìm id tiện ích mở rộng, hãy lấy tên composer và thay thế dấu gạch chéo thành dấu gạch ngang (ví dụ: 'fof/merge-discussions' thành 'fof-merge-discussions'). Tiện ích mở rộng có `flarum-` và `flarum-ext-` sẽ bị xoá các phần đó khỏi tên (ví dụ: 'webbinaro/flarum-calendar' thành 'webbinaro-calendar'). + +Đối với ví dụ sau, chúng tôi sẽ sử dụng tiện ích mở rộng có id là 'acme/interstellar': + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') +}); +``` + +Như vậy là xong, bây giờ bạn có thể thêm settings và permissions vào. + +:::tip Lưu ý + +Tất cả hàm đăng ký trong `ExtensionData` đều có thể sử dụng được, có nghĩa là bạn có thể thêm từng cái vào mà không cần thêm `for` nữa. + +::: + +### Đăng ký Settings + +Thêm các trường settings theo cách này được khuyến khích cho các mục đơn giản. Theo nguyên tắc chung, nếu bạn chỉ cần lưu trữ những thứ trong bảng cài đặt, điều này là đủ cho bạn. + +Để thêm một trường, gọi hàm `registerSetting` sau đó là `for` sau đó là `app.extensionData` và truyền 'object setting' vào dưới dạng tham số thứ nhất. Phía sau `ExtensionData` đã chuyển settings của bạn thành [`ItemList`](https://api.docs.flarum.org/js/master/class/src/common/utils/itemlist.ts~itemlist), bạn có thể truyền một số ưu tiên làm đối số thứ hai. + +Đây là ví dụ với trường switch (boolean): + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerSetting( + { + setting: 'acme-interstellar.coordinates', // Đây là key mà settings sẽ được lưu trong bảng settings trong cơ sở dữ liệu. + label: app.translator.trans('acme-interstellar.admin.coordinates_label'), // Label được hiển thị cho phép quản trị viên biết cài đặt này hoạt động như thế nào. + help: app.translator.trans('acme-interstellar.admin.coordinates_help'), // Văn bản trợ giúp tùy chọn có thể giải thích dài hơn về cài đặt. + type: 'boolean', // Đây là kiểu setting, các tùy chọn hợp lệ là: boolean, text (hoặc bất kỳ kiểu của ), và select. + }, + 30 // Không bắt buộc: Ưu tiên + ) +}); +``` + +Nếu bạn sử dụng `type: 'select'` đối tượng setting trông hơi khác một chút: + +```js +{ + setting: 'acme-interstellar.fuel_type', + label: app.translator.trans('acme-interstellar.admin.fuel_type_label'), + type: 'select', + options: { + 'LOH': 'Liquid Fuel', // Key trong đối tượng này là setting sẽ được lưu trữ trong cơ sở dữ liệu, giá trị là nhãn mà quản trị viên sẽ nhìn thấy (hãy nhớ sử dụng bản dịch nếu chúng có ý nghĩa trong ngữ cảnh của bạn). + 'RDX': 'Solid Fuel', + }, + default: 'LOH', +} +``` + +Ngoài ra, hãy lưu ý rằng các mục bổ sung trong đối tượng setting sẽ được sử dụng làm phần đính kèm component. Điều này có thể được sử dụng cho trình giữ chỗ, hạn chế tối thiểu / tối đa, v.v.: + +```js +{ + setting: 'acme-interstellar.crew_count', + label: app.translator.trans('acme-interstellar.admin.crew_count_label'), + type: 'number', + min: 1, + max: 10 +} +``` + +Nếu bạn muốn thêm thứ gì đó vào cài đặt như một số văn bản bổ sung hoặc đầu vào phức tạp hơn, bạn cũng có thể chuyển một lệnh gọi lại làm đối số đầu tiên trả về JSX. Lệnh gọi lại này sẽ được thực thi trong ngữ cảnh của [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) và các giá trị cài đặt sẽ không được tự động tuần tự hóa. + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerSetting(function () { + if (app.session.user.username() === 'RocketMan') { + + return ( +
+

{app.translator.trans('acme-interstellar.admin.you_are_rocket_man_label')}

+ +
+ ); + } + }) +}); +``` + +### Registering Permissions + +Tính năng mới trong bản beta 15, hiện có thể tìm thấy quyền ở 2 nơi. Giờ đây, bạn có thể xem các quyền riêng lẻ của từng tiện ích mở rộng trên trang của chúng. Tất cả các quyền vẫn có thể được tìm thấy trên trang quyền. + +Để điều đó xảy ra, các quyền phải được đăng ký với `ExtensionData`. Điều này được thực hiện theo cách tương tự như cài đặt, hãy gọi `registerPermission`. + +Arguments: + * Đối tượng quyền + * Loại quyền nào - xem các chức năng của[`PermissionGrid`](https://api.docs.flarum.org/js/master/class/src/admin/components/permissiongrid.js~permissiongrid) để biết các loại (xóa các mục khỏi tên) + * Mức độ ưu tiên của `ItemList` + +Quay lại phần mở rộng tên lửa yêu thích của chúng tôi: + +```js +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerPermission( + { + icon: 'fas fa-rocket', // Font-Awesome Icon + label: app.translator.trans('acme-interstellar.admin.permissions.fly_rockets_label'), // Permission Label + permission: 'discussion.rocket_fly', // Actual permission name stored in database (and used when checking permission). + tagScoped: true, // Whether it be possible to apply this permission on tags, not just globally. Giải thích trong đoạn tiếp theo. + }, + 'start', // Category permission will be added to on the grid + 95 // Optional: Priority + ); +}); +``` + +Nếu tiện ích của bạn tương tác với [phần mở rộng thẻ](https://github.com/flarum/tags) (điều này khá phổ biến), bạn có thể muốn một quyền để thẻ có thể mở rộng phạm vi (nghĩa là được áp dụng ở cấp thẻ, không chỉ trên toàn bộ). Bạn có thể thực hiện việc này bằng cách thêm thuộc tính `tagScoped`, như đã thấy ở trên. Các quyền bắt đầu bằng `discussion.` sẽ tự động được gắn thẻ trong phạm vi trừ khi `tagScoped: false` được chỉ định. + +Để tìm hiểu thêm về các quyền của Flarum, hãy xem [tài liệu liên quan](permissions.md). + +### Chaining Reminder + +Hãy nhớ rằng tất cả các hàm này có thể được xâu chuỗi như: + +```js +app.extensionData + .for('acme-interstellar') + .registerSetting(...) + .registerSetting(...) + .registerPermission(...) + .registerPermission(...); +``` + +### Mở rộng/Ghi đè trang mặc định + +Đôi khi bạn có những cài đặt phức tạp hơn gây rối cho các mối quan hệ hoặc chỉ muốn trang trông hoàn toàn khác. Trong trường hợp này, bạn cần cho `ExtensionData` biết rằng bạn muốn cung cấp trang của riêng mình. Lưu ý rằng `buildSettingComponent`, công dụng được sử dụng để đăng ký cài đặt bằng cách cung cấp đối tượng mô tả, có sẵn dưới dạng một phương thức trên `ExtensionPage` (mở rộng từ `AdminPage`, là cơ sở chung cho tất cả các trang quản trị với một số phương pháp sử dụng). + +Tạo một lớp mới mở rộng thành phần `Page` hoặc `ExtensionPage`: + +```js +import ExtensionPage from 'flarum/admin/components/ExtensionPage'; + +export default class StarPage extends ExtensionPage { + content() { + return ( +

Hello from the settings section!

+ ) + } +} + +``` + +Sau đó, chỉ cần chạy`registerPage`: + +```js + +import StarPage from './components/StarPage'; + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerPage(StarPage); +}); +``` + +Trang này sẽ được hiển thị thay vì mặc định. + +Bạn có thể mở rộng [ `ExtensionPage` ](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) hoặc `Page` cơ sở và tự thiết kế! + +## Composer.json Metadata + +Trong phiên bản beta 15, các trang tiện ích mở rộng dành chỗ cho thông tin bổ sung được lấy từ composer.json của tiện ích mở rộng. + +Để biết thêm thông tin, hãy xem [composer.json schema](https://getcomposer.org/doc/04-schema.md). + +| Mô tả | Bên trong composer.json | +| ---------------------------------- | ------------------------------------------------------------------ | +| discuss.flarum.org discussion link | khóa "forum" bên trong "support" | +| Tài liệu | khóa "docs" bên trong "support" | +| Hỗ trợ (email) | khóa "email" bên trong "support" | +| Trang web | khóa "homepage" | +| Quyên góp | khối khóa "funding" (Lưu ý: Chỉ liên kết đầu tiên sẽ được sử dụng) | +| Nguồn | khóa "source" bên trong "support" | diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md new file mode 100644 index 000000000..56ed30aa6 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md @@ -0,0 +1,58 @@ +# Điều chỉnh API + +Flarum comes with a builtin `Flarum\Api\Middleware\ThrottleApi` [middleware](middleware.md) for throttling requests to the API. This runs on every API route, and extensions can add their own custom logic to throttle requests. + +:::caution Forum Routes + +Some forum routes (login, register, forgot password, etc) work by calling an API route under the surface. The `ThrottleApi` middleware does not currently run for these requests, but that is planned for the future. + +::: + +## Custom Throttlers + +The format for a custom throttler is extremely simple: all you need is a closure or invokable class that takes the current request as an argument, and returns one of: + +- `false`: This explicitly bypasses throttling for this request, overriding all other throttlers +- `true`: This marks the request as to be throttled. +- `null`: This means that this throttler doesn't apply. Any other outputs will be ignored, with the same effect as `null`. + +Throttlers will be run on EVERY request, and are responsible for figuring out whether or not they apply. For example, consider Flarum's post throttler: + +```php +use DateTime; +use Flarum\Post\Post; + +function ($request) { + if (! in_array($request->getAttribute('routeName'), ['discussions.create', 'posts.create'])) { + return; + } + + $actor = $request->getAttribute('actor'); + + if ($actor->can('postWithoutThrottle')) { + return false; + } + + if (Post::where('user_id', $actor->id)->where('created_at', '>=', new DateTime('-10 seconds'))->exists()) { + return true; + } +}; +``` + +Throttlers can be added or removed via the `ThrottleApi` middleware in `extend.php`. For example: + +```php +set('throttleAll', function () { + return false; + }) + ->remove('bypassThrottlingAttribute'), + // Other extenders +]; +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/api.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/api.md new file mode 100644 index 000000000..c2810f98a --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/api.md @@ -0,0 +1,353 @@ +# API và Luồng dữ liệu + +Trong [bài viết trước](models.md), chúng ta đã tìm hiểu cách Flarum sử dụng các mô hình để tương tác với dữ liệu. Ở đây, chúng ta sẽ tìm hiểu cách lấy dữ liệu đó từ cơ sở dữ liệu đến JSON-API đến giao diện người dùng và quay lại tất cả các cách. + +:::info + +Để sử dụng REST API tích hợp sẵn như một phần của tích hợp, hãy xem [Sử dụng REST API](../rest-api.md). + +::: + +## Vòng đời API Request + +Trước khi chúng ta đi vào chi tiết về cách mở rộng API dữ liệu của Flarum, chúng ta nên suy nghĩ về vòng đời của một yêu cầu API điển hình: + +![Flarum API Flowchart](/en/img/api_flowchart.png) + +1. An HTTP request is sent to Flarum's API. Typically, this will come from the Flarum frontend, but external programs can also interact with the API. Flarum's API mostly follows the [JSON:API](https://jsonapi.org/) specification, so accordingly, requests should follow [said specification](https://jsonapi.org/format/#fetching). +2. The request is run through [middleware](middleware.md), and routed to the proper controller. You can learn more about controllers as a whole on our [routes and content documentation](routes.md). Assuming the request is to the API (which is the case for this section), the controller that handles the request will be a subclass of `Flarum\Api\AbstractSerializeController`. +3. Any modifications done by extensions to the controller via the [`ApiController` extender](#extending-api-controllers) are applied. This could entail changing sort, adding includes, changing the serializer, etc. +4. The `$this->data()` method of the controller is called, yielding some raw data that should be returned to the client. Typically, this data will take the form of a Laravel Eloquent model collection or instance, which has been retrieved from the database. That being said, the data could be anything as long as the controller's serializer can process it. Each controller is responsible for implementing its own `data` method. Note that for `PATCH`, `POST`, and `DELETE` requests, `data` will perform the operation in question, and return the modified model instance. +5. That data is run through any pre-serialization callbacks that extensions register via the [`ApiController` extender](#extending-api-controllers). +6. The data is passed through a [serializer](#serializers), which converts it from the backend, database-friendly format to the JSON:API format expected by the frontend. It also attaches any related objects, which are run through their own serializers. As we'll explain below, extensions can [add / override relationships and attributes](#attributes-and-relationships) at the serialization level. +7. The serialized data is returned as a JSON response to the frontend. +8. If the request originated via the Flarum frontend's `Store`, the returned data (including any related objects) will be stored as [frontend models](#frontend-models) in the frontend store. + +## API Endpoints + +We learned how to use models to interact with data, but we still need to get that data from the backend to the frontend. We do this by writing API Controller [routes](routes.md), which implement logic for API endpoints. + +As per the JSON:API convention, we'll want to add separate endpoints for each operation we support. Common operations are: + +- Listing instances of a model (possibly including searching/filtering) +- Getting a single model instance +- Creating a model instance +- Updating a model instance +- Deleting a single model instance + +We'll go over each type of controller shortly, but once they're written, you can add these five standard endpoints (or a subset of them) using the `Routes` extender: + +```php + (new Extend\Routes('api')) + ->get('/tags', 'tags.index', ListTagsController::class) + ->get('/tags/{id}', 'tags.show', ShowTagController::class) + ->post('/tags', 'tags.create', CreateTagController::class) + ->patch('/tags/{id}', 'tags.update', UpdateTagController::class) + ->delete('/tags/{id}', 'tags.delete', DeleteTagController::class) +``` + +:::caution + +Paths to API endpoints are not arbitrary! To support interactions with frontend models: + +- The path should either be `/prefix/{id}` for get/update/delete, or `/prefix` for list/create. +- the prefix (`tags` in the example above) must correspond to the JSON:API model type. You'll also use this model type in your serializer's `$type` attribute, and when registering the frontend model (`app.store.models.TYPE = MODEL_CLASS`). +- The methods must match the example above. + +Also, remember that route names (`tags.index`, `tags.show`, etc) must be unique! + +::: + +The `Flarum\Api\Controller` namespace contains a number of abstract controller classes that you can extend to easily implement your JSON-API resources. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically create your endpoint controllers: +```bash +$ flarum-cli make backend api-controller +``` + +::: + +### Listing Resources + +For the controller that lists your resource, extend the `Flarum\Api\Controller\AbstractListController` class. At a minimum, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a collection of models. The `data` method accepts the `Request` object and the tobscure/json-api `Document`. + +```php +use Flarum\Api\Controller\AbstractListController; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ListTagsController extends AbstractListController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + return Tag::all(); + } +} +``` + +#### Pagination + +You can allow the number of resources being **listed** to be customized by specifying the `limit` and `maxLimit` properties on your controller: + +```php + // The number of records included by default. + public $limit = 20; + + // The maximum number of records that can be requested. + public $maxLimit = 50; +``` + +You can then extract pagination information from the request using the `extractLimit` and `extractOffset` methods: + +```php +$limit = $this->extractLimit($request); +$offset = $this->extractOffset($request); + +return Tag::skip($offset)->take($limit); +``` + +To add pagination links to the JSON:API document, use the `Document::addPaginationLinks` method. + +#### Sorting + +You can allow the sort order of resources being **listed** to be customized by specifying the `sort` and `sortField` properties on your controller: + +```php + // The default sort field and order to use. + public $sort = ['name' => 'asc']; + + // The fields that are available to be sorted by. + public $sortFields = ['firstName', 'lastName']; +``` + +You can then extract sorting information from the request using the `extractSort` method. This will return an array of sort criteria which you can apply to your query: + +```php +use Illuminate\Support\Str; + +// ... + +$sort = $this->extractSort($request); +$query = Tag::query(); + +foreach ($sort as $field => $order) { + $query->orderBy(Str::snake($field), $order); +} + +return $query->get(); +``` + +#### Tìm kiếm và Lọc + +Read our [searching and filtering](search.md) guide for more information! + +### Showing a Resource + +For the controller that shows a single resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the list controller, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a single model. We'll learn about serializers [in just a bit](#serializers). + +```php +use Flarum\Api\Controller\AbstractShowController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ShowTagController extends AbstractShowController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + return Tag::findOrFail($id); + } +} +``` + +### Creating a Resource + +For the controller that creates a resource, extend the `Flarum\Api\Controller\AbstractCreateController` class. This is the same as the show controller, except the response status code will automatically be set to `201 Created`. You can access the incoming JSON:API document body via `$request->getParsedBody()`: + +```php +use Flarum\Api\Controller\AbstractCreateController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class CreateTagController extends AbstractCreateController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $attributes = Arr::get($request->getParsedBody(), 'data.attributes'); + + return Tag::create([ + 'name' => Arr::get($attributes, 'name') + ]); + } +} +``` + +### Updating a Resource + +For the controller that updates a resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the create controller, you can access the incoming JSON:API document body via `$request->getParsedBody()`. + +### Deleting a Resource + +For the controller that deletes a resource, extend the `Flarum\Api\Controller\AbstractDeleteController` class. You only need to implement a `delete` method which enacts the deletion. The controller will automatically return an empty `204 No Content` response. + +```php +use Flarum\Api\Controller\AbstractDeleteController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; + +class DeleteTagController extends AbstractDeleteController +{ + protected function delete(Request $request) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + Tag::findOrFail($id)->delete(); + } +} +``` + +### Including Relationships + +To include relationships when **listing**, **showing**, or **creating** your resource, specify them in the `$include` and `$optionalInclude` properties on your controller: + +```php + // The relationships that are included by default. + public $include = ['user']; + + // Other relationships that are available to be included. + public $optionalInclude = ['discussions']; +``` + +You can then get a list of included relationships using the `extractInclude` method. This can be used to eager-load the relationships on your models before they are serialized: + +```php +$relations = $this->extractInclude($request); + +return Tag::all()->load($relations); +``` + +### Extending API Controllers + +It is possible to customize all of these options on _existing_ API controllers too via the `ApiController` extender + +```php +use Flarum\Api\Event\WillGetData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->setSerializer(MyDiscussionSerializer::class) + ->addInclude('user') + ->addOptionalInclude('posts') + ->setLimit(20) + ->setMaxLimit(50) + ->setSort(['name' => 'asc']) + ->addSortField('firstName') + ->prepareDataQuery(function ($controller) { + // Add custom logic here to modify the controller + // before data queries are executed. + }) +] +``` + +The `ApiController` extender can also be used to adjust data before serialization + +```php +use Flarum\Api\Event\WillSerializeData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->prepareDataForSerialization(function ($controller, $data, $request, $document) { + $data->load('myCustomRelation'); + }), +] +``` + +## Serializers + +Before we can send our data to the frontend, we need to convert it to JSON:API format so that it can be consumed by the frontend. You should become familiar with the [JSON:API specification](https://jsonapi.org/format/). Flarum's JSON:API layer is powered by the [tobscure/json-api](https://github.com/tobscure/json-api) library. + +A serializer is just a class that converts some data (usually [Eloquent models](models.md#backend-models)) into JSON:API. Serializers serve as intermediaries between backend and frontend models: see the [model documentation](models.md) for more information. To define a new resource type, create a new serializer class extending `Flarum\Api\Serializer\AbstractSerializer`. You must specify a resource `$type` and implement the `getDefaultAttributes` method which accepts the model instance as its only argument: + +```php +use Flarum\Api\Serializer\AbstractSerializer; +use Flarum\Api\Serializer\UserSerializer; + +class DiscussionSerializer extends AbstractSerializer +{ + protected $type = 'discussions'; + + protected function getDefaultAttributes($discussion) + { + return [ + 'title' => $discussion->title, + ]; + } +} +``` + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically create your serializer: +```bash +$ flarum-cli make backend api-serializer +``` + +::: + +### Attributes and Relationships + +You can also specify relationships for your resource. Simply create a new method with the same name as the relation on your model, and return a call to `hasOne` or `hasMany` depending on the nature of the relationship. You must pass in the model instance and the name of the serializer to use for the related resources. + +```php + protected function user($discussion) + { + return $this->hasOne($discussion, UserSerializer::class); + } +``` + +### Extending Serializers + +To add **attributes** and **relationships** to an existing resource type, use the `ApiSerializer` extender: + +```php +use Flarum\Api\Serializer\UserSerializer; + +return [ + (new Extend\ApiSerializer(UserSerializer::class)) + // One attribute at a time + ->attribute('firstName', function ($serializer, $user, $attributes) { + return $user->first_name + }) + // Multiple modifications at once, more complex logic + ->mutate(function($serializer, $user, $attributes) { + $attributes['someAttribute'] = $user->someAttribute; + if ($serializer->getActor()->can('administrate')) { + $attributes['someDate'] = $serializer->formatDate($user->some_date); + } + + return $attributes; + }) + // API relationships + ->hasOne('phone', PhoneSerializer::class) + ->hasMany('comments', CommentSerializer::class), +] +``` + +### Non-Model Serializers and `ForumSerializer` + +Serializers don't have to correspond to Eloquent models: you can define JSON:API resources for anything. For instance, Flarum core uses the [`Flarum\Api\Serializer\ForumSerializer`](https://api.docs.flarum.org/php/master/flarum/api/serializer/forumserializer) to send an initial payload to the frontend. This can include settings, whether the current user can perform certain actions, and other data. Many extensions add data to the payload by extending the attributes of `ForumSerializer`. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/assets.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/assets.md new file mode 100644 index 000000000..8e262066e --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/assets.md @@ -0,0 +1,7 @@ +# Assets Tiện ích mở rộng + +Một số tiện ích mở rộng có thể muốn bao gồm các nội dung như hình ảnh hoặc tệp JSON trong mã nguồn của chúng (lưu ý rằng điều này không giống với tệp tải lên, có thể sẽ yêu cầu [đĩa filesystem](filesystem.md)). + +This is actually very easy to do. Just create an `assets` folder at the root of your extension, and place any asset files there. Flarum will then automatically copy those files to its own `assets` directory (or other storage location if [one is offered by extensions](filesystem.md)) every time the extension is enabled or [`php flarum assets:publish`](../console.md) is executed. + +If using the default storage driver, assets will be available at `https://FORUM_URL/assets/extensions/EXTENSION_ID/file.path`. However, since other extensions might use remote filesystems, we recommend serializing the url to assets you need in the backend. See [Flarum's serialization of the logo and favicon URLs](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Serializer/ForumSerializer.php#L85-L86) for an example. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md new file mode 100644 index 000000000..25f882d4e --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md @@ -0,0 +1,206 @@ +# Ủy quyền + +As with any framework, Flarum allows certain actions and content to be restricted to certain users. There are 2 parallel systems for this: + +- The authorization process dictates whether a user can take a certain action. +- Visibility scoping can be applied to a database query to efficiently restrict the records that users can access. This is documented in our [model visibility](model-visibility.md) article. + +## Quy trình ủy quyền + +Quá trình ủy quyền được sử dụng để kiểm tra xem một người có được phép thực hiện các hành động nhất định hay không. Ví dụ: chúng tôi muốn kiểm tra xem người dùng có được ủy quyền hay không trước khi họ: + +- Access the admin dashboard +- Bắt đầu một cuộc thảo luận +- Chỉnh sửa bài viết +- Cập nhật hồ sơ của người dùng khác + +Each of these is determined by unique criteria: in some cases a flag is sufficient; otherwise, we might need custom logic. + +## Cách nó hoạt động + +Truy vấn ủy quyền được thực hiện với 3 tham số, với logic có trong [`Flarum\User\Gate`](https://api.docs.flarum.org/php/master/flarum/user/access/gate): + +1. Tác nhân: người dùng cố gắng thực hiện hành động +2. Khả năng: một chuỗi đại diện cho hành động mà tác nhân đang cố gắng +3. The arguments: usually an instance of a database model which is the subject of the attempted ability, but could be anything. + +First, we run the entire request (all three parameters) through all [policies](#policies) registered by extensions and core. Policies are blocks of logic provided by core and extensions that determine whether the actor can perform the ability on the arguments. Policies can return one of the following: + +- `Flarum\User\Access\AbstractPolicy::ALLOW` (via `$this->allow()`) +- `Flarum\User\Access\AbstractPolicy::DENY` (via `$this->deny()`) +- `Flarum\User\Access\AbstractPolicy::FORCE_ALLOW` (via `$this->forceAllow()`) +- `Flarum\User\Access\AbstractPolicy::FORCE_DENY` (via `$this->forceDeny()`) + +Policy results are considered in the priority `FORCE_DENY` > `FORCE_ALLOW` > `DENY` > `ALLOW`. For example, if a single policy returns `FORCE_DENY`, all other policies will be ignored. If one policy returns `DENY` and 10 policies return `ALLOW`, the request will be denied. This allows decisions to be made regardless of the order in which extensions are booted. Note that policies are extremely powerful: if access is denied at the policy stage, that will override group permissions and even admin privileges. + +Secondly, if all policies return null (or don't return anything), we check if the user is in a group that has a permission equal to the ability (note that both permissions and abilities are represented as strings). If so, we authorize the action. See our [Groups and Permissions documentation](permissions.md) for more information on permissions. + +Then, if the user is in the admin group, we will authorize the action. + +Finally, as we have exhausted all checks, we will assume that the user is unauthorized and deny the request. + +## How To Use Authorization + +Flarum's authorization system is accessible through public methods of the `Flarum\User\User` class. The most important ones are listed below; others are documented in our [PHP API documentation](https://api.docs.flarum.org/php/master/flarum/user/user). + + +In this example, we will use `$actor` as an instance of `Flarum\User\User`, `'viewForum'` and `'reply'` as examples of abilities, and `$discussion` (instance of `Flarum\Discussion\Discussion`) as an example argument. + +```php +// Check whether a user can perform an action. +$canDoSomething = $actor->can('viewForum'); + +// Check whether a user can perform an action on a subject. +$canDoSomething = $actor->can('reply', $discussion); + +// Raise a PermissionDeniedException if a user cannot perform an action. +$actor->assertCan('viewForum'); +$actor->assertCan('reply', $discussion); + +// Raise a NotAuthenticatedException if the user is not logged in. +$actor->assertRegistered(); + +// Raise a PermissionDeniedException if the user is not an admin. +$actor->assertAdmin(); + +// Check whether one of the user's groups have a permission. +// WARNING: this should be used with caution, as it doesn't actually +// run through the authorization process, so it doesn't account for policies. +// It is, however, useful in implementing custom policies. +$actorHasPermission = $actor->hasPermission(`viewForum`); +``` + +## Custom Policies + +Policies allow us to use custom logic beyond simple groups and permissions when evaluating authorization for an ability with a subject. For instance: + +- We want to allow users to edit posts even if they aren't moderators, but only their own posts. +- Depending on settings, we might allow users to rename their own discussions indefinitely, for a short period of time after posting, or not at all. + +As described [above](#how-it-works), on any authorization check, we query all policies registered for the target's model, or any parent classes of the target's model. If no target is provided, any policies registered as `global` will be applied. + +So, how does a policy get "checked"? + +First, we check if the policy class has a method with the same name as the ability being evaluated. If so, we run it with the actor and subject as parameters. Nếu phương thức đó trả về giá trị khác rỗng, chúng tôi trả về kết quả đó. Otherwise, we continue to the next step (not necessarily the next policy). + +Then, we check if the policy class has a method called `can`. If so, we run it with the actor, ability, and subject, and return the result. + +If `can` doesn't exist or returns null, we are done with this policy, and we proceed to the next one. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate policies: +```bash +$ flarum-cli make backend policy +``` + +::: + +### Example Policies + +Let's take a look at an example policy from [Flarum Tags](https://github.com/flarum/tags/blob/master/src/Access): + +```php +is_restricted) { + return $actor->hasPermission('tag'.$tag->id.'.startDiscussion') ? $this->allow() : $this->deny(); + } + } + + /** + * @param User $actor + * @param Tag $tag + * @return bool|null + */ + public function addToDiscussion(User $actor, Tag $tag) + { + return $this->startDiscussion($actor, $tag); + } +} +``` + +We can also have global policies, which are run when `$user->can()` is called without a target model instance. Again from Tags: + +```php +settings = $settings; + } + + /** + * @param Flarum\User\User $actor + * @param string $ability + * @return bool|void + */ + public function can(User $actor, string $ability) + { + if (in_array($ability, ['viewForum', 'startDiscussion'])) { + $enoughPrimary = count(Tag::getIdsWhereCan($actor, $ability, true, false)) >= $this->settings->get('min_primary_tags'); + $enoughSecondary = count(Tag::getIdsWhereCan($actor, $ability, false, true)) >= $this->settings->get('min_secondary_tags'); + + if ($enoughPrimary && $enoughSecondary) { + return $this->allow(); + } else { + return $this->deny(); + } + } + } +} +``` + +### Registering Policies + +Both model-based and global policies can be registered with the `Policy` extender in your `extend.php` file: + +```php +use Flarum\Extend; +use Flarum\Tags\Tag; +use YourNamespace\Access; + +return [ + // Other extenders + (new Extend\Policy()) + ->modelPolicy(Tag::class, Access\TagPolicy::class) + ->globalPolicy(Access\GlobalPolicy::class), + // Other extenders +]; +``` + +## Frontend Authorization + +Commonly, you'll want to use authorization results in frontend logic. For example, if a user doesn't have permission to see search users, we shouldn't send requests to that endpoint. And if a user doesn't have permission to edit users, we shouldn't show menu items for that. + +Because we can't do authorization checks in the frontend, we have to perform them in the backend, and attach them to serialization of data we're sending. Global permissions (`viewForum`, `viewUserList`) can be included on the `ForumSerializer`, but for object-specific authorization, we may want to include those with the subject object. For instance, when we return lists of discussions, we check whether the user can reply, rename, edit, and delete them, and store that data on the frontend discussion model. It's then accessible via `discussion.canReply()` or `discussion.canEdit()`, but there's nothing magic there: it's just another attribute sent by the serializer. + +For an example of how to attach data to a serializer, see a [similar case for transmitting settings](settings.md#accessing-settings). diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md new file mode 100644 index 000000000..f36fc4041 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md @@ -0,0 +1,172 @@ +# Sự kiện Backend + +Often, an extension will want to react to some events occuring elsewhere in Flarum. For instance, we might want to increment a counter when a new discussion is posted, send a welcome email when a user logs in for the first time, or add tags to a discussion before saving it to the database. These events are known as **domain events**, and are broadcasted across the framework through [Laravel's event system](https://laravel.com/docs/8.x/events). + +For a full list of backend events, see our [API documentation](https://api.docs.flarum.org/php/master/search.html?search=Event). Domain events classes are organized by namespace, usually `Flarum\TYPE\Event`. + + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate event listeners: +```bash +$ flarum-cli make backend event-listener +``` + +::: + +## Listening to Events + +You can attach a listener to an event using the [`Event`](https://api.docs.flarum.org/php/master/flarum/extend/event) [extender](start.md#extenders): + +```php +use Flarum\Extend; +use Flarum\Post\Event\Deleted; +use Symfony\Contracts\Translation\TranslatorInterface; + + +return [ + (new Extend\Event) + ->listen(Deleted::class, function($event) { + // do something here + }) + ->listen(Deleted::class, PostDeletedListener::class) +]; +``` +```php +class PostDeletedListener +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function handle(Deleted $event) + { + // Your logic here + } +} +``` + +As shown above, a listener class can be used instead of a callback. This allows you to [inject dependencies](https://laravel.com/docs/8.x/container) into your listener class via constructor parameters. In this example we resolve a translator instance, but we can inject anything we want/need. + +You can also listen to multiple events at once via an event subscriber. This is useful for grouping common functionality; for instance, if you want to update some metadata on changes to posts: + +```php +use Flarum\Extend; +use Flarum\Post\Event\Deleted; +use Flarum\Post\Event\Saving; +use Symfony\Contracts\Translation\TranslatorInterface; + + +return [ + (new Extend\Event) + ->subscribe(PostEventSubscriber::class), +]; +``` +```php +class PostEventSubscriber +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function subscribe($events) + { + $events->listen(Deleted::class, [$this, 'handleDeleted']); + $events->listen(Saving::class, [$this, 'handleSaving']); + } + + public function handleDeleted(Deleted $event) + { + // Your logic here + } + + public function handleSaving(Saving $event) + { + // Your logic here + } +} +``` + +## Dispatching Events + +Dispatching events is very simple. All you need to do is inject `Illuminate\Contracts\Events\Dispatcher` into your class, and then call its `dispatch` method. For instance: + +```php +use Flarum\Post\Event\Deleted; +use Illuminate\Contracts\Events\Dispatcher; + + +class SomeClass +{ + /** + * @var Dispatcher + */ + protected $events; + + /** + * @param Dispatcher $events + */ + public function __construct(Dispatcher $events) + { + $this->events = $events; + } + + public function someMethod() + { + // Logic + $this->events->dispatch( + new Deleted($somePost, $someActor) + ); + // More Logic + } +} +``` + +## Custom Events + +As an extension developer you can define your own events to allow yourself (or other extensions) to react to events in your extension. Các sự kiện nói chung là các thể hiện của các lớp đơn giản (không cần mở rộng bất cứ điều gì). When defining a new event, you'll typically want to use public properties, and maybe some methods for convenience of users. For example, if we take a look at `Flarum\Post\Event\Deleted`, it's just a wrapping around some data: + +```php +post = $post; + $this->actor = $actor; + } +} +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/cli.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/cli.md new file mode 100644 index 000000000..973329601 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/cli.md @@ -0,0 +1,15 @@ +# Flarum CLI + +Hệ sinh thái phát triển Flarum được định hướng xung quanh nhiều mô-đun nhỏ, phần mở rộng tương tác. Đây là một mô hình rất mạnh mẽ và linh hoạt, nhưng nó cũng mang lại chi phí bảo trì cho việc tạo và duy trì tất cả các phần mở rộng này. + +Chúng tôi đã tạo Flarum CLI (giao diện dòng lệnh) như một công cụ để trợ giúp các nhà phát triển bằng cách tự động hóa một số tác vụ lặp đi lặp lại và thường xuyên, đồng thời cho phép họ tham gia vào công việc thực tế mà không gặp nhiều rắc rối. + +Các cập nhật chính về Flarum CLI sẽ được công bố [trong cuộc thảo luận này](https://discuss.flarum.org/d/28427-flarum-cli-v10). + +Xem [readme của gói](https://github.com/flarum/cli#readme) để biết thông tin về: + +- Cài đặt +- Sử dụng +- Nâng cấp +- Các lệnh có sẵn +- Một số chi tiết triển khai, nếu bạn quan tâm diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/console.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/console.md new file mode 100644 index 000000000..471d19681 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/console.md @@ -0,0 +1,70 @@ +# Console + +Flarum allows extension developers to add custom console commands in addition to the [default ones](../console.md) provided by flarum core. + +All console command development is done in the backend using PHP. To create a custom console command, you'll need to create a class that extends `\Flarum\Console\AbstractCommand`. + +```php +use Flarum\Console\AbstractCommand; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; + +class YourCommand extends AbstractCommand { + protected function configure() + { + $this + ->setName('YOUR COMMAND NAME') + ->setDescription('YOUR COMMAND DESCRIPTION'); + } + protected function fire() + { + // Your logic here! + } +} +``` + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate and register a console command: +```bash +$ flarum-cli make backend command +``` + +::: + +## Registering Console Commands + +To register console commands, use the `Flarum\Extend\Console` extender in your extension's `extend.php` file: + +```php +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; + +return [ + // Other extenders + (new Extend\Console())->command(CustomCommand::class) + // Other extenders +]; +``` + +## Scheduled Commands + +The `Flarum\Extend\Console`'s `schedule` method allows extension developers to create scheduled commands that run on an interval: + + +```php +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; +use Illuminate\Console\Scheduling\Event; + +return [ + // Other extenders + (new Extend\Console())->schedule('cache:clear', function (Event $event) { + $event->everyMinute(); + }, ['Arg1', '--option1', '--option2']), + // Other extenders +]; +``` + +In the callback provided as the second argument, you can call methods on the [$event object](https://laravel.com/api/8.x/Illuminate/Console/Scheduling/Event.html) to schedule on a variety of frequencies (or apply other options, such as only running on one server). See the [Laravel documentation](https://laravel.com/docs/8.x/scheduling#scheduling-artisan-commands) for more information. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md new file mode 100644 index 000000000..894391d5a --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md @@ -0,0 +1,40 @@ +# Phân bổ + +You've written a great extension — and now you want the whole world to be able to use it. This document will take you through the process of distribution, from setting up a Git repository for your extension, to publishing it on Packagist. + +## Cài đặt Git + +The first thing you'll need to do is set up a version control system (VCS). The most popular VCS is [Git](https://git-scm.com/). In this guide we'll be using Git, so make sure you have it [installed](https://git-scm.com/downloads) before continuing. If you don't have much Git knowledge, you may want to check out [these learning resources](https://try.github.io/). + +After you have installed Git, you'll need to initialize your repository. You can use `git init` on the command line if you're comfortable, or use a GUI tool like [SourceTree](https://www.sourcetreeapp.com/) or [GitKraken](https://www.gitkraken.com/). + +Then, you'll need an account in a Git hosting server, the most popular being [GitHub](https://github.com) and [GitLab](https://gitlab.com). These will instruct you on how to hook up your local repository with the online "remote" repository. + +## Gắn thẻ bản phát hành + +As you are going to be publishing this extension, you'll want to make sure that the information is up to date. Take a minute to revisit `composer.json` and make sure package name, description, and Flarum extension information are all correct. It is recommended to have a `README.md` file in your repository to explain what the extension is, so create one if you haven't already. + +When you're ready to release, commit your extension's files to the repo and tag your first version: + +```bash +git tag v0.1.0 +git push && git push --tags +``` + +## Phát hành trên Packagist + +Composer packages are published to a Composer repository, usually [Packagist](https://packagist.org/). You will need an account to proceed. + +If this is the first release you are publishing of your extension, you will need to [submit your package](https://packagist.org/packages/submit) using its public repository URL. If your extension is located on GitHub, this URL will look something like `https://github.com/AUTHOR/NAME.git`. + +### Bản phát hành tương lai + +You can set up Packagist to [auto-update packages](https://packagist.org/about#how-to-update-packages). Then for future releases, all you will need to do with Git is commit, tag, and push it to the remote server. + +## Quảng cáo tiện ích mở rộng + +You will most likely want to create a discussion on the Flarum Community in the [Extensions tag](https://discuss.flarum.org/t/extensions). Other people can install your extension using the following command: + +```bash +composer require vendor/package +``` \ No newline at end of file diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md new file mode 100644 index 000000000..9ab654f18 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md @@ -0,0 +1,122 @@ +# Extending Extensions + +Flarum extensions aren't just for adding features to core: extensions can extend other extensions! + +:::tip + +To learn how to make your extension extensible, see the [relevant documentation](extensibility.md) + +::: + +## Dependencies + +If your extension relies on another extension, you'll want to ensure that: + +- The other extension is installed and enabled before yours can be. +- The other extension can't be disabled while yours is enabled. +- The other extension is booted before your extension. + +Flarum makes this very easy: just add the other extension to your extension's `composer.json`'s `require` section. + +Ví dụ: nếu bạn đang tạo chủ đề mới cho tiện ích mở rộng thẻ Flarum, thì `composer.json` của bạn sẽ trông giống như sau: + +```json +{ + // ... + "require": { + "flarum/core": "^0.1.0-beta.15", // Since all extensions need to require core. + "flarum/tags": "^0.1.0-beta.15" // This tells Flarum to treat tags as a dependency of your extension. + }, + // ... +} +``` + +## Optional Dependencies + +Sometimes, extension A might want to extend extension B only if extension B is enabled. In this case, we call B an "Optional Dependency" of A. For instance, a drafts extension might want to add support for saving private discussion drafts, but only if the private discussion extension is enabled. + +The first step here is detecting whether extension B is enabled. In the frontend, this is easy: if extension B does anything in the frontend, its extension ID will appear as a key in the `flarum.extensions` global object. For instance: + +```js +if ('some-extension-id' in flarum.extensions) { + // do something +} +``` + +In the backend, you'll need to inject an instance of `Flarum\Extension\ExtensionManager`, and use its `isEnabled()` method. For instance: + +```php +extensions = $extensions; + } + + public function someMethod() + { + if ($this->extensions->isEnabled('some-extension-id')) { + // do something. + } + } +} +``` + +Generally, if your extension has optional dependencies, you'll want it to be booted after said optional dependencies. You can also do this by specifying composer package names (NOT flarum extension IDs) in an array for the `extra.flarum-extension.optional-dependencies` key of your composer.json. + +For instance: + +```json +{ + // ... + "extra": { + "flarum-extension": { + "optional-dependencies": [ + "flarum/tags" + ] + } + }, + // ... +} +``` + +## Importing from Extensions + +In the backend, you can import the classes you need via regular PHP `use` statements: + +```php + { + // Your Extension Code Here +}) + +export { + // Put all the stuff you want to export here. +} +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md new file mode 100644 index 000000000..5329793b8 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md @@ -0,0 +1,129 @@ +# Tập tin hệ thống + +Lõi Flarum tích hợp với hệ thống tệp để lưu trữ và phân phát nội dung (như JS / CSS đã biên dịch hoặc tải lên logos/favicons) và avatars. + +Các tiện ích mở rộng có thể sử dụng các hữu ích được cung cấp của Flarum cho nhu cầu lưu trữ tệp và tương tác với hệ thống tệp của riêng chúng. Hệ thống này dựa trên [các công cụ hệ thống tệp của Laravel](https://laravel.com/docs/8.x/filesystem), lần lượt dựa trên [thư viện Flysystem](https://github.com/thephpleague/flysystem). + +## Ổ đĩa + +Hệ thống tập tin **ổ đĩa** đại diện cho các vị trí lưu trữ và được hỗ trợ bởi các trình điều khiển lưu trữ mà chúng ta sẽ đề cập sau. Flarum cốt lõi có 2 đĩa: `flarum-assets` và `flarum-avatars`. + +### Sử dụng các ổ đĩa hiện có + +Để truy cập ổ đĩa, bạn cần truy xuất nó từ [Filesystem Factory](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Factory.html). Để làm như vậy, bạn nên đưa factory contract vào lớp của mình và truy cập vào các đĩa bạn cần. + +Hãy xem xét [`DeleteLogoController`](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Controller/DeleteLogoController.php#L19-L58) của lõi để làm ví dụ: + +```php +settings = $settings; + $this->uploadDir = $filesystemFactory->disk('flarum-assets'); + } + + /** + * {@inheritdoc} + */ + protected function delete(ServerRequestInterface $request) + { + RequestUtil::getActor($request)->assertAdmin(); + + $path = $this->settings->get('logo_path'); + + $this->settings->set('logo_path', null); + + if ($this->uploadDir->exists($path)) { + $this->uploadDir->delete($path); + } + + return new EmptyResponse(204); + } +} +``` + +The object returned by `$filesystemFactory->disk(DISK_NAME)` implements the [Illuminate\Contracts\Filesystem\Cloud](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Cloud.html) interface, and can be used to create/get/move/delete files, and to get the URL to a resource. + +### Declaring new disks + +Some extensions will want to group their resources / uploads onto a custom disk as opposed to using `flarum-assets` or `flarum-avatars`. + +This can be done via the `Filesystem` extender: + +```php +use Flarum\Extend; + +return [ + (new Extend\Filesystem) + ->disk('flarum-uploads', function (Paths $paths, UrlGenerator $url) { + return [ + 'root' => "$paths->public/assets/uploads", + 'url' => $url->to('forum')->path('assets/uploads') + ]; + }); +``` + +Since all disks use the local filesystem by default, you'll need to provide a base path and base URL for the local filesystem. + +The config array can contain other entries supported by [Laravel disk config arrays](https://laravel.com/docs/8.x/filesystem#configuration). The `driver` key should not be provided, and will be ignored. + +## Storage drivers + +Flarum selects the active driver for each disk by checking the `disk_driver.DISK_NAME` key in the [settings repository](settings.md) and [config.php file](../config.md). If no driver is configured, or the configured driver is unavailable, Flarum will default to the `local` driver. + +You can define new storage drivers by implementing the [`Flarum\Filesystem\DriverInterface` interface](https://github.com/flarum/framework/blob/main/framework/core/src/Filesystem/DriverInterface.php#L16), and registering it via the `Filesystem` extender: + +```php +use Flarum\Extend; + +return [ + (new Extend\Filesystem) + ->driver('aws-with-cdn', AwsWithCdnDriver::class); +``` + +Filesystem storage drivers are a very powerful tool that allows you to completely customize file storage locations, attach arbitrary CDNs, and otherwise extend the filesystem / cloud storage integration layer. + +:::danger + +Some drivers might try to index their filesystem every time the driver is instantiated, even if only the `url` method is needed. This can have serious performance implications. In most cases, you'll want to ensure that your driver's `url` method does not ping the remote filesystem. Similarly, the remote filesystem should usually not be accessed until operations are actually executed. + +::: + +## GUI and Admin Configuration + +Flarum does not currently provide a GUI for selecting drivers for disks, or for entering settings for drivers. This might be added in the future. For now, extensions are responsible for providing a GUI for their disks and drivers. + +As noted [above](#storage-drivers), if your extension provides a GUI for selecting drivers for a disk, it should modify the `disk_driver.DISK_NAME` key in settings. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md new file mode 100644 index 000000000..241dd18a6 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md @@ -0,0 +1,42 @@ +# Định dạng + +Flarum uses the powerful [s9e TextFormatter](https://github.com/s9e/TextFormatter) library to format posts from plain markup into HTML. You should become familiar with [how TextFormatter works](https://s9etextformatter.readthedocs.io/Getting_started/How_it_works/) before you attempt to extend it. + +In Flarum, post content is formatted with a minimal TextFormatter configuration by default. The bundled **Markdown** and **BBCode** extensions simply enable the respective plugins on this TextFormatter configuration. + +## Configuration + +You can configure the TextFormatter `Configurator` instance, as well as run custom logic during parsing and rendering, using the `Formatter` extender: + +```php +use Flarum\Extend; +use Psr\Http\Message\ServerRequestInterface as Request; +use s9e\TextFormatter\Configurator; +use s9e\TextFormatter\Parser; +use s9e\TextFormatter\Renderer; + +return [ + (new Extend\Formatter) + // Add custom text formatter configuration + ->configure(function (Configurator $config) { + $config->BBCodes->addFromRepository('B'); + }) + // Modify raw text before it is parsed. + // This callback should return the modified text. + ->parse(function (Parser $parser, $context, $text) { + // custom logic here + return $newText; + }) + // Modify the XML to be rendered before rendering. + // This callback should return the new XML. + // For example, in the mentions extension, this is used to + // provide the username and display name of the user being mentioned. + // Make sure that the last $request argument is nullable (or omitted entirely). + ->render(function (Renderer $renderer, $context, $xml, Request $request = null) { + // custom logic here + return $newXml; + }) +]; +``` + +With a good understanding of TextFormatter, this will allow you to achieve anything from simple BBCode tag additions to more complex formatting tasks like Flarum's **Mentions** extension. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/forms.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/forms.md new file mode 100644 index 000000000..af8d74fb6 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/forms.md @@ -0,0 +1,108 @@ +# Forms and Requests + +In this article, we'll go over some frontend tools that are available to us for building and managing forms, as well how to send HTTP requests via Flarum. + +## Form Components + +As with any interactive site, you will likely want to include forms in some pages and modals. Flarum provides some components to make building (and styling!) these forms easier. Please see the linked API documentation for each of these to learn more about its accepted attrs. + +- The [`flarum/common/components/FieldSet` component](https://api.docs.flarum.org/js/master/class/src/common/components/fieldset.js~fieldset) wraps its children in a HTML fieldset tag, with a legend. +- The [`flarum/common/components/Select` component](https://api.docs.flarum.org/js/master/class/src/common/components/select.js~select) is a stylized select input. +- The [`flarum/common/components/Switch`](https://api.docs.flarum.org/js/master/class/src/common/components/switch.js~switch) and [`flarum/common/components/Checkbox` components](https://api.docs.flarum.org/js/master/class/src/common/components/checkbox.js~checkbox) are stylized checkbox input components. Their `loading` attr can be set to `true` to show a loading indicator. +- The [`flarum/common/components/Button` component](https://api.docs.flarum.org/js/master/class/src/common/components/button.js~button) is a stylized button, and is used frequently throughout Flarum. + +You'll typically want to assign logic for reacting to input changes via Mithril's `on*` attrs, not external listeners (as is common with jQuery or plain JS). For example: + +```jsx +import Component from 'flarum/common/Component'; +import FieldSet from 'flarum/common/components/FieldSet'; +import Button from 'flarum/common/components/Button'; +import Switch from 'flarum/common/components/Switch'; + + +class FormComponent extends Component { + oninit(vnode) { + this.textInput = ""; + this.booleanInput = false; + } + + view() { + return ( +
+
+ this.textInput = e.target.value}> + + this.booleanInput = val}> + +
+ +
+ ) + } + + onsubmit() { + // Some form handling logic here + } +} +``` + +Don't forget to use [translations](i18n.md)! + + +## Streams, bidi, and withAttr + +Flarum provides [Mithril's Stream](https://mithril.js.org/stream.html) as `flarum/common/util/Stream`. This is a very powerful reactive data structure, but is most commonly used in Flarum as a wrapper for form data. Its basic usage is: + +```js +import Stream from 'flarum/common/utils/Stream'; + + +const value = Stream("hello!"); +value() === "hello!"; // true +value("world!"); +value() === "world!"; // true +``` + +In Flarum forms, streams are frequently used together with the bidi attr. Bidi stands for bidirectional binding, and is a common pattern in frontend frameworks. Flarum patches Mithril with the [`m.attrs.bidi` library](https://github.com/tobyzerner/m.attrs. This abstracts away input processing in Mithril. For instance: + +```jsx +import Stream from 'flarum/common/utils/Stream'; + +const value = Stream(); + +// Without bidi + value(e.target.value)}> + +// With bidi + +``` + +You can also use the `flarum/common/utils/withAttr` util for simplified form processing. `withAttr` calls a callable, providing as an argument some attr of the DOM element tied to the component in question: + +```jsx +import Stream from 'flarum/common/utils/Stream'; +import withAttr from 'flarum/common/utils/withAttr'; + +const value = Stream(); + +// With a stream + + +// With any callable + { + // Some custom logic here +})}> +``` + +## Making Requests + +In our [models](models.md) documentation, you learned how to work with models, and save model creation, changes, and deletion to the database via the Store util, which is just a wrapper around Flarum's request system, which itself is just a wrapper around [Mithril's request system](https://mithril.js.org/request.html). + +Flarum's request system is available globally via `app.request(options)`, and has the following differences from Mithril's `m.request(options)`: + +- It will automatically attach `X-CSRF-Token` headers. +- It will convert `PATCH` and `DELETE` requests into `POST` requests, and attach a `X-HTTP-Method-Override` header. +- If the request errors, it will show an alert which, if in debug mode, can be clicked to show a full error modal. +- You can supply a `background: false` option, which will run the request synchronously. However, this should almost never be done. + +Otherwise, the API for using `app.request` is the same as that for `m.request`. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md new file mode 100644 index 000000000..1d39746a3 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md @@ -0,0 +1,218 @@ +# Trang Frontend và Trình phân giải + +As explained in the [Routes and Content](routes.md#frontend-routes) documentation, we can use Mithril's routing system to show different [components](frontend.md#components) for different routes. Mithril allows you to use any component you like, even a Modal or Alert, but we recommend sticking to component classes that inherit the `Page` component. + +## Component Trang + +We provide `flarum/common/components/Page` as a base class for pages in both the `admin` and `forum` frontends. It has a few benefits: + +- Automatically updates [`app.current` and `app.previous` PageState](#pagestate) when switching from one route to another. +- Automatically closes the modal and drawer when switching from one route to another. +- Applies `this.bodyClass` (if defined) to the '#app' HTML element when the page renders. +- It's also good for consistency's sake to use a common base class for all pages. +- If the page's `scrollTopOnCreate` attribute is set to `false` in `oninit`, the page won't be scrolled to the top when changed. +- If the page's `useBrowserScrollRestoration` is set to `false` in `oninit`, the browser's automatic scroll restoration won't be used on that page. + +Page components work just like any other inherited component. For a (very simple) example: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + view() { + return

Hello!

+ } +} +``` + +### Đặt Trang làm Trang chủ + +Flarum uses a setting to determine which page should be the homepage: this gives admins flexibility to customize their communities. To add your custom page to the homepage options in Admin, you'll need to extend the `BasicsPage.homePageItems` method with your page's path. + +An example from the [Tags extension](https://github.com/flarum/tags/blob/master/js/src/admin/addTagsHomePageOption.js): + +```js +import { extend } from 'flarum/common/extend'; +import BasicsPage from 'flarum/common/components/BasicsPage'; + +export default function() { + extend(BasicsPage.prototype, 'homePageItems', items => { + items.add('tags', { + path: '/tags', + label: app.translator.trans('flarum-tags.admin.basics.tags_label') + }); + }); +} +``` + +To learn how to set up a path/route for your custom page, see the [relevant documentation](routes.md). + +### Tiêu đề trang + +Often, you'll want some custom text to appear in the browser tab's title for your page. For instance, a tags page might want to show "Tags - FORUM NAME", or a discussion page might want to show the title of the discussion. + +To do this, your page should include calls to `app.setTitle()` and `app.setTitleCount()` in its `oncreate` [lifecycle hook](frontend.md) (or when data is loaded, if it pulls in data from the API). + +For example: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + oncreate(vnode) { + super.oncreate(vnode); + + app.setTitle("Cool Page"); + app.setTitleCount(0); + } + + view() { + // ... + } +} + +export default class CustomPageLoadsData extends Page { + oninit(vnode) { + super.oninit(vnode); + + app.store.find("users", 1).then(user => { + app.setTitle(user.displayName()); + app.setTitleCount(0); + }) + } + + view() { + // ... + } +} +``` + +Please note that if your page is [set as the homepage](#setting-page-as-homepage), `app.setTitle()` will clear the title for simplicity. It should still be called though, to prevent titles from previous pages from carrying over. + +## PageState + +Sometimes, we want to get information about the page we're currently on, or the page we've just come from. To allow this, Flarum creates (and stores) instances of [`PageState`](https://api.docs.flarum.org/js/master/class/src/common/states/pagestate.js~pagestate) as `app.current` and `app.previous`. These store: + +- The component class being used for the page +- A collection of data that each page sets about itself. The current route name is always included. + +Data can be set to, and retrieved from, Page State using: + +```js +app.current.set(KEY, DATA); +app.current.get(KEY); +``` + +For example, this is how the Discussion Page makes its [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) instance globally available. + +You can also check the type and data of a page using `PostStreamState`'s `matches` method. For instance, if we want to know if we are currently on a discussion page: + +```jsx +import IndexPage from 'flarum/forum/components/DiscussionPage'; +import DiscussionPage from 'flarum/forum/components/DiscussionPage'; + +// To just check page type +app.current.matches(DiscussionPage); + +// To check page type and some data +app.current.matches(IndexPage, {routeName: 'following'}); +``` + +## Admin Pages + +See the [Admin Dashboard documentation](admin.md) for more information on tools specifically available to admin pages (and how to override the admin page for your extension). + +## Route Resolvers (Advanced) + +[Advanced use cases](https://mithril.js.org/route.html#advanced-component-resolution) can take advantage of Mithril's [route resolver system](https://mithril.js.org/route.html#routeresolver). Flarum actually already wraps all its components in the `flarum/common/resolvers/DefaultResolver` resolver. This has the following benefits: + +- It passes a `routeName` attr to the current page, which then provides it to `PageState` +- It assigns a [key](https://mithril.js.org/keys.html#single-child-keyed-fragments) to the top level page component. When the route changes, if the top level component's key has changed, it will be completely rerendered (by default, Mithril does not rerender components when switching from one page to another if both are handled by the same component). + +### Using Route Resolvers + +There are actually 3 ways to set the component / route resolver when registering a route: + +- the `resolver` key can be used to provide an **instance** of a route resolver. This instance should define which component should be used, and hardcode the route name to be passed into it. This instance will be used without any modifications by Flarum. +- The `resolverClass` key AND `component` key can be used to provide a **class** that will be used to instantiate a route resolver, to be used instead of Flarum's default one, as well as the component to use. Its constructor should take 2 arguments: `(component, routeName)`. +- The `component` key can be used alone to provide a component. This will result in the default behavior. + +For example: + +```js +// See above for a custom page example +import CustomPage from './components/CustomPage'; +// See below for a custom resolver example +import CustomPageResolver from './resolvers/CustomPageResolver'; + +// Use a route resolver instance +app.routes['resolverInstance'] = {path: '/custom/path/1', resolver: { + onmatch: function(args) { + if (!app.session.user) return m.route.SKIP; + + return CustomPage; + } +}}; + +// Use a custom route resolver class +app.routes['resolverClass'] = {path: '/custom/path/2', resolverClass: CustomPageResolver, component: CustomPage}; + +// Use the default resolver class (`flarum/common/resolvers/DefaultResolver`) +app.routes['resolverClass'] = {path: '/custom/path/2', component: CustomPage}; +``` + +### Custom Resolvers + +We strongly encourage custom route resolvers to extend `flarum/common/resolvers/DefaultResolver`. For example, Flarum's `flarum/forum/resolvers/DiscussionPageResolver` assigns the same key to all links to the same discussion (regardless of the current post), and triggers scrolling when using `m.route.set` to go from one post to another on the same discussion page: + +```js +import DefaultResolver from '../../common/resolvers/DefaultResolver'; + +/** + * This isn't exported as it is a temporary measure. + * A more robust system will be implemented alongside UTF-8 support in beta 15. + */ +function getDiscussionIdFromSlug(slug: string | undefined) { + if (!slug) return; + return slug.split('-')[0]; +} + +/** + * A custom route resolver for DiscussionPage that generates the same key to all posts + * on the same discussion. It triggers a scroll when going from one post to another + * in the same discussion. + */ +export default class DiscussionPageResolver extends DefaultResolver { + static scrollToPostNumber: number | null = null; + + makeKey() { + const params = { ...m.route.param() }; + if ('near' in params) { + delete params.near; + } + params.id = getDiscussionIdFromSlug(params.id); + return this.routeName.replace('.near', '') + JSON.stringify(params); + } + + onmatch(args, requestedPath, route) { + if (route.includes('/d/:id') && getDiscussionIdFromSlug(args.id) === getDiscussionIdFromSlug(m.route.param('id'))) { + DiscussionPageResolver.scrollToPostNumber = parseInt(args.near); + } + + return super.onmatch(args, requestedPath, route); + } + + render(vnode) { + if (DiscussionPageResolver.scrollToPostNumber !== null) { + const number = DiscussionPageResolver.scrollToPostNumber; + // Scroll after a timeout to avoid clashes with the render. + setTimeout(() => app.current.get('stream').goToNumber(number)); + DiscussionPageResolver.scrollToPostNumber = null; + } + + return super.render(vnode); + } +} +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md new file mode 100644 index 000000000..7146b83c1 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md @@ -0,0 +1,422 @@ +# Phát triển Frontend + +This page describes how to make changes to Flarum's user interface. How to add buttons, marquees, and blinking text. 🤩 + +[Remember](/extend/start.md#architecture), Flarum's frontend is a **single-page JavaScript application**. There's no Twig, Blade, or any other kind of PHP template to speak of. The few templates that are present in the backend are only used to render search-engine-optimized content. All changes to the UI need to be made via JavaScript. + +Flarum has two separate frontend applications: + +* `forum`, the public side of your forum where users create discussions and posts. +* `admin`, the private side of your forum where, as an administrator of your forum, you configure your Flarum installation. + +They share the same foundational code, so once you know how to extend one, you know how to extend both. + +:::tip Typings! + +Along with new TypeScript support, we have a [`tsconfig` package](https://www.npmjs.com/package/flarum-tsconfig) available, which you should install as a dev dependency to gain access to our typings. Make sure you follow the instructions in the [package's README](https://github.com/flarum/flarum-tsconfig#readme) to configure typings support. + +::: + +## Biên dịch và cấu trúc tập tin + +This portion of the guide will explain the necessary file setup for extensions. Once again, we highly recommend using the [Flarum CLI](https://github.com/flarum/cli) to set up the file structure for you. That being said, you should still read this to understand what's going on beneath the surface. + +Before we can write any JavaScript, we need to set up a **transpiler**. This allows us to use [TypeScript](https://www.typescriptlang.org/) and its magic in Flarum core and extensions. + +In order to do this transpilation, you need to be working in a capable environment. No, not the home/office kind of environment – you can work in the bathroom for all I care! I'm talking about the tools that are installed on your system. You'll need: + +* Node.js and npm ([Download](https://nodejs.org/en/download/)) +* Webpack (`npm install -g webpack`) + +This can be tricky because everyone's system is different. From the OS you're using, to the program versions you have installed, to the user access permissions – I get chills just thinking about it! If you run into trouble, ~~tell him I said hi~~ use [Google](https://google.com) to see if someone has encountered the same error as you and found a solution. If not, ask for help from the [Flarum Community](https://discuss.flarum.org) or on the [Discord chat](https://flarum.org/discord/). + +It's time to set up our little JavaScript transpilation project. Create a new folder in your extension called `js`, then pop in a couple of new files. A typical extension will have the following frontend structure: + +``` +js +├── dist (compiled js is placed here) +├── src +│ ├── admin +│ └── forum +├── admin.js +├── forum.js +├── package.json +├── tsconfig.json +└── webpack.config.js +``` + +### package.json + +```json +{ + "private": true, + "name": "@acme/flarum-hello-world", + "dependencies": { + "flarum-webpack-config": "^1.0.0", + "webpack": "^4.0.0", + "webpack-cli": "^4.0.0" + }, + "devDependencies": { + "flarum-tsconfig": "^1.0.0" + }, + "scripts": { + "dev": "webpack --mode development --watch", + "build": "webpack --mode production" + } +} +``` + +This is a standard JS [package-description file](https://docs.npmjs.com/files/package.json), used by npm and Yarn (Javascript package managers). You can use it to add commands, js dependencies, and package metadata. We're not actually publishing a npm package: this is simply used to collect dependencies. + +Please note that we do not need to include `flarum/core` or any flarum extensions as dependencies: they will be automatically packaged when Flarum compiles the frontends for all extensions. + +### webpack.config.js + +```js +const config = require('flarum-webpack-config'); + +module.exports = config(); +``` + +[Webpack](https://webpack.js.org/concepts/) is the system that actually compiles and bundles all the javascript (and its dependencies) for our extension. To work properly, our extensions should use the [official flarum webpack config](https://github.com/flarum/flarum-webpack-config) (shown in the above example). + +### tsconfig.json + +```json +{ + // Use Flarum's tsconfig as a starting point + "extends": "flarum-tsconfig", + // This will match all .ts, .tsx, .d.ts, .js, .jsx files in your `src` folder + // and also tells your Typescript server to read core's global typings for + // access to `dayjs` and `$` in the global namespace. + "include": ["src/**/*", "../vendor/flarum/core/js/dist-typings/@types/**/*"], + "compilerOptions": { + // This will output typings to `dist-typings` + "declarationDir": "./dist-typings", + "baseUrl": ".", + "paths": { + "flarum/*": ["../vendor/flarum/core/js/dist-typings/*"] + } + } +} +``` + +This is a standard configuration file to enable support for Typescript with the options that Flarum needs. + +Always ensure you're using the latest version of this file: https://github.com/flarum/flarum-tsconfig#readme. + +Even if you choose not to use TypeScript in your extension, which is supported natively by our Webpack config, it's still recommended to install the `flarum-tsconfig` package and to include this configuration file so that your IDE can infer types for our core JS. + +To get the typings working, you'll need to run `composer update` in your extension's folder to download the latest copy of Flarum's core into a new `vendor` folder. Remember not to commit this folder if you're using a version control system such as Git. + +You may also need to restart your IDE's TypeScript server. In Visual Studio Code, you can press F1, then type "Restart TypeScript Server" and hit ENTER. This might take a minute to complete. + +### admin.js và forum.js + +These files contain the root of our actual frontend JS. You could put your entire extension here, but that would not be well organized. For this reason, we recommend putting the actual source code in `src`, and having these files just export the contents of `src`. For instance: + +```js +// admin.js +export * from './src/admin'; + +// forum.js +export * from './src/forum'; +``` + +### src + +If following the recommendations for `admin.js` and `forum.js`, we'll want to have 2 subfolders here: one for `admin` frontend code, and one for `forum` frontend code. If you have components, models, utils, or other code that is shared across both frontends, you may want to create a `common` subfolder and place it there. + +Structure for `admin` and `forum` is identical, so we'll just show it for `forum` here: + +``` +src/forum/ +├── components/ +|-- models/ +├── utils/ +└── index.js +``` + +`components`, `models`, and `utils` are directories that contain files where you can define custom [components](#components), [models](models.md#frontend-models), and reusable util helper functions. Please note that this is all simply a recommendation: there's nothing forcing you to use this particular file structure (or any other file structure). + +The most important file here is `index.js`: everything else is just extracting classes and functions into their own files. Let's go over a typical `index.js` file structure: + +```js +import { extend, override } from 'flarum/common/extend'; + +// We provide our extension code in the form of an "initializer". +// This is a callback that will run after the core has booted. +app.initializers.add('acme-flarum-hello-world', function(app) { + // Your Extension Code Here + console.log("EXTENSION NAME is working!"); +}); +``` + +We'll go over tools available for extensions below. + +### Nhập + +You should familiarize yourself with proper syntax for [importing js modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import), as most extensions larger than a few lines will split their js into multiple files. + +Pretty much every Flarum extension will need to import *something* from Flarum Core. Like most extensions, core's JS source code is split up into `admin`, `common`, and `forum` folders. You can import the file by prefixing its path in the Flarum core source code with `flarum`. So `admin/components/AdminLinkButton` is available as `flarum/admin/components/AdminLinkButton`, `common/Component` is available as `flarum/common/Component`, and `forum/states/PostStreamState` is available as `flarum/forum/states/PostStreamState`. + +In some cases, an extension may want to extend code from another flarum extension. This is only possible for extensions which explicitly export their contents. + +* `flarum/tags` and `flarum/flags` are currently the only bundled extensions that allow extending their JS. You can import their contents from `flarum/{EXT_NAME}/PATH` (e.g. `flarum/tags/components/TagHero`). +* The process for extending each community extension is different; you should consult documentation for each individual extension. + +### Biên dịch + +OK, time to fire up the transpiler. Run the following commands in the `js` directory: + +```bash +npm install +npm run dev +``` + +This will compile your browser-ready JavaScript code into the `js/dist/forum.js` file, and keep watching for changes to the source files. Nifty! + +When you've finished developing your extension (or before a new release), you'll want to run `npm run build` instead of `npm run dev`: this builds the extension in production mode, which makes the source code smaller and faster. + +## Đăng ký asset + +### JavaScript + +In order for your extension's JavaScript to be loaded into the frontend, we need to tell Flarum where to find it. We can do this using the `Frontend` extender's `js` method. Add it to your extension's `extend.php` file: + +```php +js(__DIR__.'/js/dist/forum.js') +]; +``` + +Flarum will make anything you `export` from `forum.js` available in the global `flarum.extensions['acme-hello-world']` object. Thus, you may choose to expose your own public API for other extensions to interact with. + +:::tip External Libraries + +Only one main JavaScript file per extension is permitted. If you need to include any external JavaScript libraries, either install them with NPM and `import` them so they are compiled into your JavaScript file, or see [Routes and Content](/extend/routes.md) to learn how to add extra `'; + }) +]; +``` + +You can also add content onto your frontend route registrations: + +```php +return [ + (new Extend\Frontend('forum')) + ->route('/users', 'acme.users', function (Document $document, Request $request) { + $document->title = 'Users'; + }) +]; +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/search.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/search.md new file mode 100644 index 000000000..e22b5f116 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/search.md @@ -0,0 +1,202 @@ +# Tìm kiếm và Lọc + +Flarum treats searching and filtering as parallel but distinct processes. Which process is used to handle a request to a [`List` API endpoint](/extend/api.md#api-endpoints) depends on the query parameters: + +- Filtering is applied when the `filter[q]` query param is omitted. Filters represent **structured** queries: for instance, you might want to only retrieve discussions in a certain category, or users who registered before a certain date. Filtering computes results based entirely on `filter[KEY] = VALUE` query parameters. +- Searching is applied when the `filter[q]` query param is included. Searches represent **unstructured** queries: the user submits an arbitrary string, and data records that "match" it are returned. For instance, you might want to search discussions based on the content of their posts, or users based on their username. Searching computes results based solely on parsing the `filter[q]` query param: all other `filter[KEY] = VALUE` params are ignored when searching. It's important to note that searches aren't entirely unstructured: the dataset being searched can be constrained by gambits (which are very similar to filters, and will be explained later). + +This distinction is important because searches and filters have very different use cases: filters represent *browsing*: that is, the user is passively looking through some category of content. In contrast, searches represent, well, *searching*: the user is actively looking for content based on some criteria. + +Flarum implements searching and filtering via per-model `Searcher` and `Filterer` classes (discussed in more detail below). Both classes accept a [`Flarum\Query\QueryCriteria`](https://api.docs.flarum.org/php/master/flarum/query/querycriteria) instance (a wrapper around the user and query params), and return a [`Flarum\Query\QueryResults`](https://api.docs.flarum.org/php/master/flarum/query/queryresults) instance (a wrapper around an Eloquent model collection). This common interface means that adding search/filter support to models is quite easy. + +One key advantage of this split is that it allows searching to be implemented via an external service, such as ElasticSearch. For larger communities, this can be significantly more performant and accurate. There isn't a dedicated extender for this yet, so for now, replacing the default Flarum search driver requires overriding the container bindings of `Searcher` classes. This is a highly advanced use case; if you're interested in doing this, please reach out on our [community forums](https://discuss.flarum.org/). + +Remember that the [JSON:API schema](https://jsonapi.org/format) is used for all API requests. + +:::tip Reuse Code + +Often, you might want to use the same class as both a `Filter` and a `Gambit` (both explained below). Your classes can implement both interface; see Flarum core's [`UnreadFilterGambit`](https://github.com/flarum/framework/blob/main/framework/core/src/Discussion/Query/UnreadFilterGambit.php) for an example. + +::: + +:::tip Query Builder vs Eloquent Builder + +`Filter`s, `Gambit`s, filter mutators, and gambit mutators (all explained below) receive a "state" parameter, which wraps + +::: + +## Filtering + +Filtering constrains queries based on `Filters` (highlighted in code to avoid confusion with the process of filtering), which are classes that implement `Flarum\Filter\FilterInterface` and run depending on query parameters. After filtering is complete, a set of callbacks called "filter mutators" run for every filter request. + +When the `filter` method on a `Filterer` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Filter/AbstractFilterer.php#L50-L93)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Filterer` class's `getQuery()` method. +2. We loop through all `filter[KEY] = VALUE` query params. For each of these, any `Filter`s registered to the model whose `getFilterKey()` method matches the query param `KEY` is applied. `Filter`s can be negated by providing the query param as `filter[-KEY] = VALUE`. Whether or not a `Filter` is negated is passed to it as an argument: implementing negation is up to the `Filter`s. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "filter mutators" are applied. These are callbacks that receive the filter state (a wrapper around the query builder and current user) and filter criteria, and perform some arbitrary changes. All "filter mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Filtering for an Existing Model + +Let's say you've added a `country` column to the User model, and would like to filter users by country. We'll need to define a custom `Filter`: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +Note that `FilterState` is a wrapper around the Eloquent builder's underlying Query builder and the current user. + +Also, let's pretend that for some reason, we want to omit any users that have a different country from the current user on ANY filter. We can use a "filter mutator" for this: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +Now, all we need to do is register these via the Filter extender: + +```php + // Other extenders + (new Extend\Filter(UserFilterer::class)) + ->addFilter(CountryFilter::class) + ->addFilterMutator(OnlySameCountryFilterMutator::class), + // Other extenders +``` + +### Add Filtering to a New Model + +To filter a model that doesn't support filtering, you'll need to create a subclass of `Flarum/Filter/AbstractFilterer` for that model. For an example, see core's [UserFilterer](https://github.com/flarum/framework/blob/main/framework/core/src/User/Filter/UserFilterer.php). + +Then, you'll need to use that filterer in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +## Searching + +Searching constrains queries by applying `Gambit`s, which are classes that implement `Flarum\Search\GambitInterface`, based on the `filter[q]` query param. After searching is complete, a set of callbacks called "search mutators" run for every search request. + +When the `search` method on a `Searcher` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Search/AbstractSearcher.php#L55-L79)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Searcher` class's `getQuery()` method. +2. The `filter[q]` param is split by spaces into "tokens". Each token is matched against the model's registered `Gambit`s (each gambit has a `match` method). For any tokens that match a gambit, that gambit is applied, and the token is removed from the query string. Once all regular `Gambit`s have ran, all remaining unmatched tokens are passed to the model's `FullTextGambit`, which implements the actual searching logic. For example if searching discussions, in the `filter[q]` string `'author:1 hello is:hidden' world`, `author:1` and `is:hidden` would get matched by core's Author and Hidden gambits, and `'hello world'` (the remaining tokens) would be passed to the `DiscussionFulltextGambit`. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "search mutators" are applied. These are callbacks that receive the search state (a wrapper around the query builder and current user) and criteria, and perform some arbitrary changes. All "search mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Searching for an Existing Model + +Let's reuse the "country" examples we used above, and see how we'd implement the same things for searching: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +:::warning No Spaces in Gambit Patterns! + +Flarum splits the `filter[q]` string into tokens by splitting it at spaces. This means that your custom gambits can NOT use spaces as part of their pattern. + +::: + +:::tip AbstractRegexGambit + +All a gambit needs to do is implement `Flarum\Search\GambitInterface`, which receives the search state and a token. It should return if this gambit applies for the given token, and if so, make whatever mutations are necessary to the query builder accessible as `$searchState->getQuery()`. + +However, for most gambits, the `AbstractRegexGambit` abstract class (used above) should be used as a base class. This makes it a lot simpler to match and apply gambits. + +::: + +Similarly, the search mutator we need is almost identical to the filter mutator from before: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +We can register these via the `SimpleFlarumSearch` extender (in the future, the `Search` extender will be used for registering custom search drivers): + +```php + // Other extenders + (new Extend\SimpleFlarumSearch(UserSearcher::class)) + ->addGambit(CountryGambit::class) + ->addSearchMutator(OnlySameCountrySearchMutator::class), + // Other extenders +``` + +### Add Searching to a New Model + +To support searching for a model, you'll need to create a subclass of `Flarum/Search/AbstractSearcher` for that model. For an example, see core's [UserSearcher](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/UserSearcher.php). + +Then, you'll need to use that searcher in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +Every searcher **must** have a fulltext gambit (the logic that actually does the searching). Otherwise, it won't be booted by Flarum, and you'll get an error. See core's [FulltextGambit for users](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/Gambit/FulltextGambit.php) for an example. You can set (or override) the full text gambit for a searcher via the `SimpleFlarumSearch` extender's `setFullTextGambit()` method. + +### Search Drivers + +Coming soon! + +## Frontend Tools + +Coming soon! diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md new file mode 100644 index 000000000..07e3e4d91 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md @@ -0,0 +1,65 @@ +# Service Provider + +As noted throughout this documentation, Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection. [Service Providers](https://laravel.com/docs/8.x/providers) allow low-level configuration and modification of the Flarum backend. The most common use case for service providers is to create, modify, or replace container bindings. That being said, service providers allow you full access to run whatever logic you need during application boot with access to the container. + +:::caution Advanced Use Only!!! + +Unlike with other extenders, the Service Provider layer is NOT use-case driven, and is NOT considered public API. It is subject to change at any time, without notice or deprecation. This should only be used if you know what you're doing, and the other extenders don't satisfy your use case. + +::: + +## Flarum Boot Process + +To understand service providers, you must first understand the order in which Flarum boots. Most of this happens in [Flarum\Foundation\InstalledSite](https://github.com/flarum/framework/blob/main/framework/core/src/Foundation/InstalledSite.php) + +1. The container and application are initialized, and essential bindings (config, environment, logger) are registered +2. The `register` methods of all core service providers are run. +3. The `extend` methods of all extenders used by all enabled extensions are run. +4. The `extend` methods of all extenders used in the Flarum site's local `extend.php` are run. +5. The `boot` methods of all core service providers are run. + +## Custom Service Providers + +A custom service provider should extend `Flarum\Foundation\AbstractServiceProvider`, and can have a `boot` and a `register` method. For example: + +```php +container->resolving(SomeClass::class, function ($container) { + return new SomeClass($container->make('some.binding')); + }); + } + + public function boot(Container $container) + { + // custom logic here + } +} +``` + +The `register` method will run during step (3) above, and the `boot` method will run during step (5) above. In the `register` method, the container is available via `$this->container`. In the `boot` method, the container (or any other arguments), should be injected via typehinted method arguments. + +Flarum does not currently support Laravel Octane, but some [best practices](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane), like using the `$container` argument inside `bind`, `singleton`, and `resolving` callbacks instead of `$this->container` should be used. See the [Octane documentation](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane) for more information. + +To actually register your custom service provider, you can use the `ServiceProvider` extender in `extend.php`: + +```php +register(CustomServiceProvider::class), + // Other extenders +]; +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/settings.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/settings.md new file mode 100644 index 000000000..ffefdcde5 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/settings.md @@ -0,0 +1,90 @@ +# Settings + +At some point while making an extension, you might want to read some of the forum's settings or store certain settings specific to your extension. Thankfully, Flarum makes this very easy. + +## The Settings Repository + +Reading or changing settings can be done using an implementation of the `SettingsRepositoryInterface`. Because Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection, you don't need to worry about where to obtain such a repository, or how to instantiate one. Instead, you can rely on the container to instantiate your class and inject the correct dependencies. + +```php +settings = $settings; + } +} +``` + +Great! Now the `SettingsRepositoryInterface` is available through `$this->settings` to our class. + +### Reading Settings + +To read settings, all we have to do is use the repository's `get()` function: + +`$this->settings->get('forum_title')` + +The `get()` function accepts two arguments: + +1. The name of the setting you are trying to read. +2. (Optional) A default value if no value has been stored for such a setting. By default, this will be `null`. + +### Storing Settings + +Storing settings ist just as easy, use the `set()` function: + +`$this->settings->set('forum_title', 'Super Awesome Forum')` + +The `set` function also accepts two arguments: + +1. The name of the setting you are trying to change. +2. The value you want to store for this setting. + +### Other Functions + +The `all()` function returns an array of all known settings. + +The `delete($name)` function lets you remove a named setting. + +## Settings in the Frontend + +### Editing Settings + +To learn more about adding settings through the admin dashboard, see the [relevant documentation](admin.md). +### Accessing Settings + +All settings are available in the `admin` frontend via the `app.data.settings` global. However, this is not done in the `forum` frontend, as anyone can access it, and you wouldn't want to leak all your settings! (Seriously, that could be a very problematic data breach). + +Instead, if we want to use settings in the `forum` frontend, we'll need to serialize them and send them alongside the initial forum data payload. + +This can be done via the `Settings` extender. For example: + +**extend.php** + +```php +use Flarum\Extend; + +return [ + (new Extend\Settings) + ->serializeToForum('myCoolSetting', 'my.cool.setting.key') + ->serializeToForum('myCoolSettingModified', 'my.cool.setting.key', function ($retrievedValue) { + // This third argument is optional, and allows us to pass the retrieved setting through some custom logic. + // In this example, we'll append a string to it. + + return "My Cool Setting: $retrievedValue"; + }, "default value!"), +] +``` + +Now, the `my.cool.setting.key` setting will be accessible in the frontend as `app.forum.attribute("myCoolSetting")`, and our modified value will be accessible via `app.forum.attribute("myCoolSettingModified")`. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md new file mode 100644 index 000000000..3dc39416b --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md @@ -0,0 +1 @@ +# Model Slugging diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/start.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/start.md new file mode 100644 index 000000000..88fa6ed95 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/start.md @@ -0,0 +1,153 @@ +# Bắt đầu + +Want to build a Flarum extension? You've come to the right place! This document will take you through some essential concepts, after which you'll build your first Flarum extension from scratch. + +## Cấu tạo + +Để hiểu cách mở rộng Flarum, trước tiên chúng ta cần hiểu một chút về cách Flarum được xây dựng. + +Be aware that Flarum uses some _modern_ languages and tools. If you've only ever built WordPress plugins before, you might feel a bit out of your depth! That's OK — this is a great time to learn cool new things and extend your skillset. However, we would advise that you become somewhat familiar with the technologies described below before proceeding. + +Flarum được tạo thành từ ba lớp: + +* First, there is the **backend**. This is written in [object-oriented PHP](https://laracasts.com/series/object-oriented-bootcamp-in-php), and makes use of a wide array of [Laravel](https://laravel.com/) components and other packages via [Composer](https://getcomposer.org/). You'll also want to familiarize yourself with the concept of [Dependency Injection](https://laravel.com/docs/8.x/container), which is used throughout our backend. + +* Second, the backend exposes a **public API** which allows frontend clients to interface with your forum's data. This is built according to the [JSON:API specification](https://jsonapi.org/). + +* Finally, there is the default web interface which we call the **frontend**. This is a [single-page application](https://en.wikipedia.org/wiki/Single-page_application) which consumes the API. It's built with a simple React-like framework called [Mithril.js](https://mithril.js.org). + +Extensions will often need to interact with all three of these layers to make things happen. For example, if you wanted to build an extension that adds custom fields to user profiles, you would need to add the appropriate database structures in the **backend**, expose that data in the **public API**, and then display it and allow users to edit it on the **frontend**. + +So... how do we extend these layers? + +## Bộ mở rộng + +In order to extend Flarum, we will be using a concept called **extenders**. Extenders are *declarative* objects that describe in plain terms the goals you are trying to achieve (such as adding a new route to your forum, or executing some code when a new discussion was created). + +Every extender is different. However, they will always look somewhat similar to this: + +```php +// Đăng ký JavaScript và tệp CSS để được gửi bằng frontend của diễn đàn +(new Extend\Frontend('forum')) + ->js(__DIR__.'/forum-scripts.js') + ->css(__DIR__.'/forum-styles.css') +``` + +You first create an instance of the extender, and then call methods on it for further configuration. All of these methods return the extender itself, so that you can achieve your entire configuration just by chaining method calls. + +To keep things consistent, we use this concept of extenders in both the backend (in PHP land) and the frontend (in JavaScript land). _Everything_ you do in your extension should be done via extenders, because they are a **guarantee** we are giving to you that a future minor release of Flarum won't break your extension. + +All of the extenders currently available to you from Flarum's core can be found in the [`Extend` namespace](https://github.com/flarum/framework/blob/main/framework/core/src/Extend) [(PHP API documentation)](https://api.docs.flarum.org/php/master/flarum/extend) Extensions may also offer their [own extenders](extensibility.md#custom-extenders). + +## Hello World + +Want to see an extender in action? The `extend.php` file in the root of your Flarum installation is the easiest way to register extenders just for your site. It should return an array of extender objects. Pop it open and add the following: + +```php +content(function (Document $document) { + $document->head[] = ''; + }) +]; +``` + +Now pay your forum a visit for a pleasant (albeit extremely obtrusive) greeting. 👋 + +For simple site-specific customizations – like adding a bit of custom CSS/JavaScript, or integrating with your site's authentication system – the `extend.php` file in your forum's root is great. But at some point, your customization might outgrow it. Or maybe you have wanted to build an extension to share with the community from the get-go. Time to build an extension! + +## Gói Tiện ích mở rộng + +[Composer](https://getcomposer.org) is a dependency manager for PHP. It allows applications to easily pull in external code libraries and makes it easy to keep them up-to-date so that security and bug fixes are propagated rapidly. + +As it turns out, every Flarum extension is also a Composer package. That means someone's Flarum installation can "require" a certain extension and Composer will pull it in and keep it up-to-date. Nice! + +During development, you can work on your extensions locally and set up a [Composer path repository](https://getcomposer.org/doc/05-repositories.md#path) to install your local copy. Create a new `packages` folder in the root of your Flarum installation, and then run this command to tell Composer that it can find packages in here: + +```bash +composer config repositories.0 path "packages/*" +``` + +Now let's start building our first extension. Make a new folder inside `packages` for your extension called `hello-world`. We'll put two files in it: `extend.php` and `composer.json`. These files serve as the heart and soul of the extension. + +### extend.php + +The `extend.php` file is just like the one in the root of your site. It will return an array of extender objects that tell Flarum what you want to do. For now, just move over the `Frontend` extender that you had earlier. + +### composer.json + +Chúng tôi cần cho Composer biết một chút về gói của chúng tôi và chúng tôi có thể làm điều này bằng cách tạo tệp `composer.json`: + +```json +{ + "name": "acme/flarum-hello-world", + "description": "Say hello to the world!", + "type": "flarum-extension", + "require": { + "flarum/core": "^1.0.0" + }, + "autoload": { + "psr-4": {"Acme\\HelloWorld\\": "src/"} + }, + "extra": { + "flarum-extension": { + "title": "Hello World", + "icon": { + "name": "fas fa-smile", + "backgroundColor": "#238c59", + "color": "#fff" + } + } + } +} +``` + +* **name** là tên của gói Composer ở định dạng `vendor/package`. + * You should choose a vendor name that’s unique to you — your GitHub username, for example. For the purposes of this tutorial, we’ll assume you’re using `acme` as your vendor name. + * Bạn nên đặt tiền tố phần `package` bằng `flarum-`để cho biết rằng đó là một gói được thiết kế đặc biệt để sử dụng với Flarum. + +* **description** là một mô tả ngắn một câu về chức năng của tiện ích. + +* **type** MUST be set to `flarum-extension`. This ensures that when someone "requires" your extension, it will be identified as such. + +* **require** chứa danh sách các phần phụ thuộc của tiện ích mở rộng của bạn. + * Bạn sẽ muốn chỉ định phiên bản Flarum mà tiện ích mở rộng của bạn tương thích tại đây. + * Đây cũng là nơi liệt kê các thư viện Composer khác mà mã của bạn cần để hoạt động. + +* **autoload** tells Composer where to find your extension's classes. The namespace in here should reflect your extensions' vendor and package name in CamelCase. + +* **extra.flarum-extension** chứa một số thông tin cụ thể về Flarum, như tên hiển thị của tiện ích mở rộng của bạn và biểu tượng của nó trông như thế nào. + * **title** là tên hiển thị của tiện ích mở rộng của bạn. + * **icon** is an object which defines your extension's icon. The **name** property is a [Font Awesome icon class name](https://fontawesome.com/icons). All other properties are used as the `style` attribute for your extension's icon. + +Xem tài liệu [lược đồ composer.json](https://getcomposer.org/doc/04-schema.md) để biết thông tin về các thuộc tính khác mà bạn có thể thêm vào `composer.json`. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +Sử dụng CLI để tự động tạo giàn giáo cho tiện ích mở rộng của bạn: +```bash +$ flarum-cli init +``` + +::: + +### Cài đặt Tiện ích mở rộng của bạn + +The final thing we need to do to get up and running is to install your extension. Navigate to the root directory of your Flarum install and run the following command: + +```bash +composer require acme/flarum-hello-world *@dev +``` + +Sau khi hoàn tất, hãy tiếp tục và kích hoạt trên trang Quản trị của diễn đàn, sau đó điều hướng trở lại diễn đàn của bạn. + +*tiếng vù vù, vù vù, tiếng kêu kim loại* + +Woop! Hello to you too, extension! + +We're making good progress. We've learned how to set up our extension and use extenders, which opens up a lot of doors. Read on to learn how to extend Flarum's frontend. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md new file mode 100644 index 000000000..28e6c4aa7 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md @@ -0,0 +1,86 @@ +# Static Code Analysis + +Static code analysis is the process of analyzing the source code against a set of rules to find bugs, code smells, and security vulnerabilities. This is a great way to improve the quality of your code and to find potential issues before they are deployed to production. An example is validating the typings of a function to ensure that the function is called with the correct arguments. + +Flarum provides a static code analysis package based on [PHPStan](https://phpstan.org/) that can be added to your extension. In this guide, we will show you how to add the package to your extension and how to run the analysis. + +## Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update the infrastructure for phpstan to your code: + +```bash +$ flarum-cli infra phpstan +``` + +::: + +First you need to require the `flarum/phpstan` package in your extension. You can do this by running the following command in the root of our extension: + +```bash +composer require --dev flarum/phpstan:^1.0 +``` + +Next, you need to create a `phpstan.neon` file in the root of your extension. This file contains [the configuration for PHPStan](https://phpstan.org/config-reference). You can copy the following configuration into the file: + +```neon +includes: + - vendor/flarum/phpstan/extension.neon + +parameters: + # The level will be increased in Flarum 2.0 + level: 5 + paths: + - src + - extend.php + excludePaths: + - *.blade.php + checkMissingIterableValueType: false + databaseMigrationsPath: ['migrations'] +``` + +Finally, you need to add the following script to your `composer.json` file: + +```json +{ + "scripts": { + "analyse:phpstan": "phpstan analyse", + "clear-cache:phpstan": "phpstan clear-result-cache" + }, + "scripts-descriptions": { + "analyse:phpstan": "Run static analysis" + } +} +``` + +## Running the analysis + +To run the analysis, you can run the following command in the root of your extension: + +```bash +composer analyse:phpstan +``` + +If you want to clear the cache before running the analysis, you can run the following command: + +```bash +composer clear-cache:phpstan && composer analyse:phpstan +``` + +## GitHub Actions + +You can also run the analysis using GitHub Actions. Checkout the page on [GitHub Actions](github-actions.md) for more information. + +## Tips + +### Extended model attribute types + +PHPStan needs to be able to determine the type of an attribute added to an existing model. To do this you can use the `Extend\Model(...)->cast(...)` method. + +For example, if your extension were to add a `is_cool` attribute to the `User` model, you can use [attribute casting](https://laravel.com/docs/8.x/eloquent-mutators#attribute-casting) to explicitly define the attribute as boolean. The `flarum/phpstan` package will automatically detect this and communicate it to PHPStan. + +```php +(new Extend\Model(User::class)) + ->cast('is_cool', 'bool'), +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/testing.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/testing.md new file mode 100644 index 000000000..f9d866094 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/testing.md @@ -0,0 +1,565 @@ +# Testing + +Automated testing ensures that your extension performs as you expect it to, helps avoid introducing new bugs or regressions, and saves time on manual testing. Flarum currently provides tooling for automated backend unit and integration tests, and we plan to release support for frontend unit testing and E2E testing in the future. + +## Backend Tests + +The `flarum/testing` library is used by core and some bundled extensions for automated unit and integration tests. It is essentially a collection of utils that allow testing Flarum core and extensions with PHPUnit. + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update backend testing infrastructure to your code: + +```bash +$ flarum-cli infra backendTesting +``` + +::: + +```bash +composer require --dev flarum/testing:^1.0 +``` + +Then, you will need to set up a file structure for tests, and add PHPUnit configuration: + +``` +tests +├── fixtures (put any files needed by your tests here (blade templates, images, etc)) +├── integration +│ ├── setup.php (code below) +│ └── PUT INTEGRATION TESTS HERE (organizing into folder is generally a good idea) +├── unit +│ ├── PUT UNIT TESTS HERE +├── phpunit.integration.xml (code below) +└── phpunit.unit.xml (code below) +``` + +#### phpunit.integration.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for integration tests. You can tweak this as needed, but keep `backupGlobals`, `backupStaticAttributes`, and `processIsolation` unchanged. + +```xml + + + + + + + ./integration + + + +``` + +#### phpunit.unit.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for unit tests. You can tweak this as needed. + +```xml + + + + + + + ./unit + + + + + + +``` + +#### setup.php + +This script will be run to set up a testing database / file structure. + +```php +run(); +``` + +#### composer.json Modifications + +We will also want to add scripts to our `composer.json`, so that we can run our test suite via `composer test`. Add some variant of the following to your `composer.json`: + +```json +"scripts": { + "test": [ + "@test:unit", + "@test:integration" + ], + "test:unit": "phpunit -c tests/phpunit.unit.xml", + "test:integration": "phpunit -c tests/phpunit.integration.xml", + "test:setup": "@php tests/integration/setup.php" +}, +"scripts-descriptions": { + "test": "Runs all tests.", + "test:unit": "Runs all unit tests.", + "test:integration": "Runs all integration tests.", + "test:setup": "Sets up a database for use with integration tests. Execute this only once." +} +``` + +#### Github Testing Workflow + +To run tests on every commit and pull request, check out the [GitHub Actions](github-actions.md) page. + +--- + +Now that we have everything in place, we need to set up our testing site for integration tests. For this, we will need a MySQL or MariaDb instance, and a place to store testing files. + +Testing database information is configured via the `DB_HOST` (defaults to `localhost`), `DB_PORT` (defaults to `3306`), `DB_DATABASE` (defaults to `flarum_test`), `DB_USERNAME` (defaults to `root`), `DB_PASSWORD` (defaults to `root`), and `DB_PREFIX` (defaults to `''`) environmental variables. The testing tmp directory path is configured via the `FLARUM_TEST_TMP_DIR_LOCAL` or `FLARUM_TEST_TMP_DIR` environmental variables, with the former taking precedence over the latter. If neither are provided, a `tmp` directory will be created in the `vendor` folder of your extension's local install. + +Now that we've provided the needed information, all we need to do is run `composer test:setup` in our extension's root directory, and we have our testing environment ready to go! + +Since [(almost)](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/tests/integration/api/discussions/ListWithFulltextSearchTest.php#L29-L45) all database operations in integration tests are run in transactions, developers working on multiple extensions will generally find it more convenient to use one shared database and tmp directory for testing all their extensions. To do this, set the database config and `FLARUM_TEST_TMP_DIR` environmental variables in your `.bashrc` or `.bash_profile` to the path you want to use, and run the setup script for any one extension (you'll still want to include the setup file in every repo for CI testing via GitHub Actions). You should then be good to go for any Flarum extension (or core). + +### Using Integration Tests + +Flarum's integration test utils are contained in the `Flarum\Testing\integration\TestCase` class. It: + +- Boots (and makes available) an instance of the Flarum application. +- Allows pre-populating the database, enabling extensions, and adding extenders. +- Runs all database changes in transactions, so your test database retains the default post-installation state. +- Allows sending requests through the middleware stack to test HTTP endpoints. + +Your testcase classes should extend this class. + +#### Test Case Setup + +There are several important utilities available for your test cases: + +- The `setting($key, $value)` method allows you to override settings before the app has booted. This is useful if your boot process has logic depending on settings (e.g. which driver to use for some system). +- Similarly, the `config($key, $value)` method allows you to override config.php values before the app has booted. You can use dot-delimited keys to set deep-nested values in the config array. +- The `extension($extensionId)` method will take Flarum IDs of extensions to enable as arguments. Your extension should always call this with your extension's ID at the start of test cases, unless the goal of the test case in question is to confirm some behavior present without your extension, and compare that to behavior when your extension is enabled. If your extension is dependent on other extensions, make sure they are included in the composer.json `require` field (or `require-dev` for [optional dependencies](extending-extensions.md)), and also list their composer package names when calling `extension()`. Note that you must list them in a valid order. +- The `extend($extender)` method takes instances of extenders as arguments, and is useful for testing extenders introduced by your extension for other extensions to use. +- The `prepareDatabase()` method allow you to pre-populate your database. This could include adding users, discussions, posts, configuring permissions, etc. Its argument is an associative array that maps table names to arrays of [record arrays](https://laravel.com/docs/8.x/queries#insert-statements). + +If your test case needs users beyond the default admin user, you can use the `$this->normalUser()` method of the `Flarum\Testing\integration\RetrievesAuthorizedUsers` trait. + +:::warning + +The `TestCase` class will boot a Flarum instance the first time its `app()` method is called. Any uses of `prepareDatabase`, `extend`, or `extension` after this happens will have no effect. Make sure you have done all the setup you need in your test case before calling `app()`, or `database()`, `server()`, or `send()`, which call `app()` implicitly. If you need to make database modifications after the app has booted, you can use the regular Eloquent save method, or the `Illuminate\Database\ConnectionInterface` instance obtained via calling the `database()` method. + +::: + +Of course, since this is all based on PHPUnit, you can use the `setUp()` methods of your test classes for common setup tasks. + +For example: + +```php +setting('my.custom.setting', true); + + // Let's assume our extension depends on tags. + // Note that tags will need to be in your extension's composer.json's `require-dev`. + // Also, make sure you include the ID of the extension currently being tested, unless you're + // testing the baseline without your extension. + $this->extension('flarum-tags', 'my-cool-extension'); + + // Note that this input isn't validated: make sure you're populating with valid, representative data. + $this->prepareDatabase([ + 'users' => [ + $this->normalUser() // Available for convenience. + ], + 'discussions' => [ + ['id' => 1, 'title' => 'some title', 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 1, 'first_post_id' => 1, 'comment_count' => 1] + ], + 'posts' => [ + ['id' => 1, 'number' => 1, 'discussion_id' => 1, 'created_at' => Carbon::now(), 'user_id' => 1, 'type' => 'comment', 'content' => '

something

'] + ] + ]); + + // Most test cases won't need to test extenders, but if you want to, you can. + $this->extend((new CoolExtensionExtender)->doSomething('hello world')); + } + + /** + * @test + */ + public function some_phpunit_test_case() + { + // ... + } + + // ... +} +``` + +#### Sending Requests + +A common application of automated testing is pinging various HTTP endpoints with various data, authenticated as different users. You can use this to ensure that: + +- Users can't access content they're not supported to access. +- Permission-based create/edit/delete operations perform as expected. +- The type and schema of data returned is correct. +- Some desired side effect is applied when pinging an API. +- The basic API operations needed by your extension aren't erroring, and don't break when you make changes. + +`TestCase` provides several utilities: + +- The `request()` method constructs a `Psr\Http\Message\ServerRequestInterface` implementing object from a path, a method, and some options, which can be used for authentication, attaching cookies, or configuring the JSON request body. See the [method docblock](https://github.com/flarum/testing/blob/main/src/integration/TestCase.php) for more information on available options. +- Once you've created a request instance, you can send it (and get a response object back) via the `send()` method. + +For example: + +```php +send( + $this->request('GET', '/api/users', ['authenticatedAs' => 1]) + ->withQueryParams(['filter' => ['q' => 'john group:1'], 'sort' => 'username']) + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + /** + * @test + */ + public function can_create_user() + { + $response = $this->send( + $this->request( + 'POST', + '/api/users', + [ + 'authenticatedAs' => 1, + 'json' => [ + 'data' => [ + 'attributes' => [ + 'username' => 'test', + 'password' => 'too-obscure', + 'email' => 'test@machine.local' + ] + ] + ] + ] + ) + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + // ... +} +``` + +:::caution + +If you want to send query parameters in a GET request, you can't include them in the path; you'll need to add them afterwards with the `withQueryParams` method. + +::: + +:::caution + +This is an extreme edge case, but note that MySQL does not update the fulltext index in transactions, so the standard approach won't work if you're trying to test a modified fulltext query. See [core's approach](https://github.com/flarum/framework/blob/main/framework/core/tests/integration/extenders/SimpleFlarumSearchTest.php) for an example of a workaround. + +::: + +#### Console Tests + +If you want to test custom console commands, you can extend `Flarum\Testing\integration\ConsoleTestCase` (which itself extends the regular `Flarum\Testing\integration\TestCase`). It provides 2 useful methods: + +- `$this->console()` returns an instance of `Symfony\Component\Console\Application` +- `$this->runCommand()` takes an array that will be wrapped in `Symfony\Component\Console\Input\ArrayInput`, and run. See the [Symfony code docblock](https://github.com/symfony/console/blob/5.x/Input/ArrayInput.php#L22) for more information. + +For example: + +```php + 'some:command', // The command name, equivalent of `php flarum some:command` + 'foo' => 'bar', // arguments + '--lorem' => 'ipsum' // options + ]; + + $this->assertEquals('Some Output.', $this->runCommand($input)); + } +} +``` + +### Using Unit Tests + +Unit testing in Flarum uses [PHPUnit](https://phpunit.de/getting-started/phpunit-9.html) and so unit testing in flarum is much like any other PHP application. You can find [general tutorials on testing](https://www.youtube.com/watch?v=9-X_b_fxmRM) if you're also new to php. + +When writing unit tests in Flarum, here are some helpful tips. + +#### Mocking Flarum Services + +Unlike the running app, or even integration tests, there is no app/container/etc to inject service instances into our classes. Now all the useful settings, or helpers your extension use require a _mock_ . We want to limit mocking to just the key services, supporting only the minimum interactions needed to test the contract of our individual functions. + +```php + public function setUp(): void + { + parent::setUp(); + // example - if our setting needs settings, we can mock the settings repository + $settingsRepo = m::mock(SettingsRepositoryInterface::class); + // and then control specific return values for each setting key + $settingsRepo->shouldReceive('get')->with('some-plugin-key')->andReturn('some-value-useful-for-testing'); + // construct your class under test, passing mocked services as needed + $this->serializer = new YourClassUnderTest($settingsRepo); + } +``` + +Some aspects require more mocks. If you're validating authorization interactions for instance you might need to mock your users `User::class` and the request's method that provides them as well! + +``` + $this->actor = m::mock(User::class); + $request = m::mock(Request::class)->makePartial(); + $request->shouldReceive('getAttribute->getActor')->andReturn($this->actor); + $this->actor->shouldReceive('SOME PERMISSION')->andReturn(true/false); +``` + +NOTE: If you find your extension needs _lots and lots_ of mocks, or mocks that feel unrelated, it might be an opportunity to simplify your code, perhaps moving key logic into their own smaller functions (that dont require mocks). + +## Frontend Tests + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update frontend testing infrastructure to your code: + +```bash +$ flarum-cli infra frontendTesting +``` + +::: + +First, you need to install the Jest config dev dependency: + +```bash +$ yarn add --dev @flarum/jest-config +``` + +Then, add the following to your `package.json`: + +```json +{ + "type": "module", + "scripts": { + ..., + "test": "yarn node --experimental-vm-modules $(yarn bin jest)" + } +} +``` + +Rename `webpack.config.js` to `webpack.config.cjs`. This is necessary because Jest doesn't support ESM yet. + +Create a `jest.config.cjs` file in the root of your extension: + +```js +module.exports = require('@flarum/jest-config')(); +``` + +If you are using TypeScript, create tsconfig.test.json with the following content: + +```json +{ + "extends": "./tsconfig.json", + "include": ["tests/**/*"], + "files": ["../../../node_modules/@flarum/jest-config/shims.d.ts"] +} +``` + +Then, you will need to set up a file structure for tests: + +``` +js +├── dist +├── src +├── tests +│ ├── unit +│ │ └── functionTest.test.js +│ ├── integration +│ │ └── componentTest.test.js +├── package.json +├── tsconfig.json +├── tsconfig.test.json +├── jest.config.cjs +└── webpack.config.cjs +``` + +#### Github Testing Workflow + +To run tests on every commit and pull request, check out the [GitHub Actions](github-actions.md) page. + +### Using Unit Tests + +Like any other JS project, you can use Jest to write unit tests for your frontend code. Checkout the [Jest docs](https://jestjs.io/docs/using-matchers) for more information on how to write tests. + +Here's a simple example of a unit test fo core's `abbreviateNumber` function: + +```ts +import abbreviateNumber from '../../../../src/common/utils/abbreviateNumber'; + +test('does not change small numbers', () => { + expect(abbreviateNumber(1)).toBe('1'); +}); + +test('abbreviates large numbers', () => { + expect(abbreviateNumber(1000000)).toBe('1M'); + expect(abbreviateNumber(100500)).toBe('100.5K'); +}); + +test('abbreviates large numbers with decimal places', () => { + expect(abbreviateNumber(100500)).toBe('100.5K'); + expect(abbreviateNumber(13234)).toBe('13.2K'); +}); +``` + +### Using Integration Tests + +Integration tests are used to test the components of your frontend code and the interaction between different components. For example, you might test that a page component renders the correct content based on certain parameters. + +Here's a simple example of an integration test for core's `Alert` component: + +```ts +import Alert from '../../../../src/common/components/Alert'; +import m from 'mithril'; +import mq from 'mithril-query'; +import { jest } from '@jest/globals'; + +describe('Alert displays as expected', () => { + it('should display alert messages with an icon', () => { + const alert = mq(m(Alert, { type: 'error' }, 'Shoot!')); + expect(alert).toContainRaw('Shoot!'); + expect(alert).toHaveElement('i.icon'); + }); + + it('should display alert messages with a custom icon when using a title', () => { + const alert = mq(Alert, { type: 'error', icon: 'fas fa-users', title: 'Woops..' }); + expect(alert).toContainRaw('Woops..'); + expect(alert).toHaveElement('i.fas.fa-users'); + }); + + it('should display alert messages with a title', () => { + const alert = mq(m(Alert, { type: 'error', title: 'Error Title' }, 'Shoot!')); + expect(alert).toContainRaw('Shoot!'); + expect(alert).toContainRaw('Error Title'); + expect(alert).toHaveElement('.Alert-title'); + }); + + it('should display alert messages with custom controls', () => { + const alert = mq(Alert, { type: 'error', controls: [m('button', { className: 'Button--test' }, 'Click me!')] }); + expect(alert).toHaveElement('button.Button--test'); + }); +}); + +describe('Alert is dismissible', () => { + it('should show dismiss button', function () { + const alert = mq(m(Alert, { dismissible: true }, 'Shoot!')); + expect(alert).toHaveElement('button.Alert-dismiss'); + }); + + it('should call ondismiss when dismiss button is clicked', function () { + const ondismiss = jest.fn(); + const alert = mq(Alert, { dismissible: true, ondismiss }); + alert.click('.Alert-dismiss'); + expect(ondismiss).toHaveBeenCalled(); + }); + + it('should not be dismissible if not chosen', function () { + const alert = mq(Alert, { type: 'error', dismissible: false }); + expect(alert).not.toHaveElement('button.Alert-dismiss'); + }); +}); +``` + +#### Methods + +These are the custom methods that are available for mithril component tests: +* **`toHaveElement(selector)`** - Checks if the component has an element that matches the given selector. +* **`toContainRaw(content)`** - Checks if the component HTML contains the given content. + +To negate any of these methods, simply prefix them with `not.`. For example, `expect(alert).not.toHaveElement('button.Alert-dismiss');`. For more information, check out the [Jest docs](https://jestjs.io/docs/using-matchers). For example you may need to check how to [mock functions](https://jestjs.io/docs/mock-functions), or how to use `beforeEach` and `afterEach` to set up and tear down tests. + + + +## E2E Tests + +Coming Soon! diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/theme.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/theme.md new file mode 100644 index 000000000..2d9d846e4 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/theme.md @@ -0,0 +1,27 @@ +# Chủ đề + +Flarum "themes" chỉ là phần mở rộng. Thông thường, bạn sẽ muốn sử dụng bộ mở rộng `Frontend` để đăng ký [Less](https://lesscss.org/#overview) và JS tùy chỉnh. Tất nhiên, bạn cũng có thể sử dụng các bộ mở rộng khác: ví dụ: bạn có thể muốn hỗ trợ cài đặt để cho phép định cấu hình chủ đề của mình. + +Bạn có thể chỉ ra rằng tiện ích của bạn là một chủ đề bằng cách đặt khóa "extra.flarum-extension.category" thành "theme". For example: + +```json +{ + // other fields + "extra": { + "flarum-extension": { + "category": "theme" + } + } + // other fields +} +``` + +Tất cả điều này sẽ làm là hiển thị tiện ích mở rộng của bạn trong phần "theme" trong danh sách tiện ích mở rộng bảng điều khiển dành cho quản trị viên. + +## Tùy biến giá trị Less + +Bạn có thể xác định các biến Less mới trong các tệp Less của tiện ích mở rộng của mình. Hiện tại không có bộ mở rộng để sửa đổi các giá trị Ít biến hơn trong lớp PHP, nhưng điều này được lên kế hoạch cho các bản phát hành trong tương lai. + +## Chuyển đổi giữa các chủ đề + +Flarum hiện không có một hệ thống toàn diện hỗ trợ chuyển đổi giữa các chủ đề. Điều này được lên kế hoạch cho các bản phát hành trong tương lai. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md new file mode 100644 index 000000000..2131181a0 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md @@ -0,0 +1,257 @@ +# Cập nhật cho 1.0 + +Flarum version 1.0 is the long-awaited stable release! This release brings a number of refactors, cleanup, and small improvements that should make your Flarum experience just a bit better! + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Full Stack + +### Translations and transChoice + +#### Background + +Historically, Flarum has used Symfony for backend translations, and a port for frontend translations to keep format consistent. There are a few limitations to this approach though: + +- Developers need to decide between using `trans` or `transChoice` for pluralization +- The pluralization format is proprietary to Symfony +- We have to maintain the JS port ourselves +- Keys for values provided to backend translations need to be wrapped in curly braces. (e.g. `$this->translator->trans('some.translation', ['{username}' => 'Some Username!'])`). +- There's no support for complex applications (nested pluralization, non-number-based selection) +- As a result of the previous point, genderization is impossible. And that's kinda important for a lot of languages. + +### New System + +In v5, Symfony dropped their proprietary `transChoice` system in favor of the more-or-less standard [ICU MessageFormat](https://symfony.com/doc/5.2/translation/message_format.html). This solves pretty much every single one of the aforementioned issues. In this release, Flarum will be fully switching to ICU MessageFormat as well. What does this mean for extensions? + +- `transChoice` should not be used at all; instead, the variable passed for pluralization should be included in the data. +- Keys for backend translations no longer need to be surrounded by curly braces. +- Translations can now use the [`select` and `plural`](https://symfony.com/doc/5.2/translation/message_format.html) formatter syntaxes. For the `plural` formatter, the `offset` parameter and `#` magic variables are supported. +- These `select` and `plural` syntaxes can be nested to arbitrary depth. This is often a bad idea though (beyond, say, 2 levels), as things can get unnecessarily complex. + +No change to translation file naming is necessary (Symfony docs say that an `+intl-icu` suffix is necessary, but Flarum will now interpret all translation files as internationalized). + +#### Future Changes + +In the future, this will serve as a basis for additional features: + +- Translator preprocessors will allow extensions to modify arguments passed to translations. This will enable genderization (extensions could automatically extract a gender field from any objects of type "user" passed in). +- We could support internationalized "magic variables" for numbers: currently, `one` is supported, but others (`few`, `many`, etc) currently aren't. +- We could support ordinal formatting in additional to just plural formatting. + +#### Changes Needed in Extensions + +The `transChoice` methods in the frontend and backend have been removed. The `trans` method should always be used for translating, regardless of pluralization. If a translation requires pluralization, make sure you pass in the controlling variable as one of the arguments. + +In the frontend, code that looked like this: + +```js +app.translator.transChoice('some-translation', guestCount, {host: hostName}); +``` + +should be changed to: + +```js +// This uses ES6 key-property shorthand notation. {guestCount: guestCount} is equivalent to {guestCount} +app.translator.trans('some-translation', {host: hostName, guestCount }); +``` + +Similarly, in the backend, + +```php +$translator->transChoice('some-translation', $guestCount, ['{host}' => $hostName]); +``` + +should be changed to: + +```php +$translator->trans('some-translation', ['host' => $hostName, 'guestCount' => $guestCount]); +``` + +Note that in the backend, translation keys were previously wrapped in curly braces. This is no longer needed. + +#### Changes Needed in Translations + +Translations that aren't using pluralization don't need any changes. + +Pluralized translations should be changed as follows: + +`For {count} minute|For {count} minutes` + +to + +`{count, plural, one {For # minute} other {For # minutes}}` + +Note that in this example, `count` is the variable that controls pluralization. If a different variable were used (such as guestCount in the example above), this would look like: + +`{guestCount, plural, one {For # minute} other {For # minutes}}` + +See [our i18n docs](i18n.md) for more information. + +### Permissions Changes + +For a long time, the `viewDiscussions` and `viewUserList` permissions have been confusing. Despite their names: + +- `viewDiscussions` controls viewing both discussions and users. +- `viewUserList` controls searching users, not viewing user profiles. + +To clear this up, in v1.0, these permissions have been renamed to `viewForum` and `searchUsers` respectively. A migration in core will automatically adjust all permissions in the database to use the new naming. However, any extension code using the old name must switch to the new ones immediately to avoid security issues. To help the transfer, a warning will be thrown if the old permissions are referenced. + +We have also slightly improved tag scoping for permissions. Currently, permissions can be applied to tags if: + +- The permission is `viewForum` +- The permission is `startDiscussion` +- The permission starts with `discussion.` + +However, this doesn't work for namespaced permissions (`flarum-acme.discussion.bookmark`), or permissions that don't really have anything to do with discussions, but should still be scoped (e.g. `viewTag`). To counter this, a `tagScoped` attribute can be used on the object passed to [`registerPermission`](admin.md) to explicitly indicate whether the permission should be tag scopable. If this attribute is not provided, the current rules will be used to determine whether the permission should be tag scopable. + +## Frontend + +### Tooltip Changes + +The `flarum/common/components/Tooltip` component has been introduced as a simpler and less framework-dependent way to add tooltips. If your code is creating tooltips directly (e.g. via `$.tooltip()` in `oncreate` methods), you should wrap your components in the `Tooltip` component instead. For example: + +```tsx + + + +``` + +See [the source code](https://github.com/flarum/core/blob/master/js/src/common/components/Tooltip.tsx) for more examples and instructions. + +See [the PR](https://github.com/flarum/core/pull/2843/files) for examples of how to change existing code to use tooltips. + +### PaginatedListState + +The `flarum/common/states/PaginatedListState` state class has been introduced to abstract away most of the logic of `DiscussionListState` and `NotificationListState`. It provides support for loading and displaying paginated lists of JSON:API resources (usually models). In future releases, we will also provide an `PaginatedList` (or `InfiniteScroll`) component that can be used as a base class for these paginated lists. + +Please see [the source code](https://github.com/flarum/core/blob/master/js/src/common/states/PaginatedListState.ts) for a list of methods. + +Note that `flarum/forum/states/DiscussionListState`'s `empty` and `hasDiscussions` methods have been removed, and replaced with `isEmpty` and `hasItems` respectively. This is a breaking change. + +### New Loading Spinner + +The old `spin.js` based loading indicator has been replaced with a CSS-based solution. For the most part, no changes should be needed in extensions, but in some cases, you might need to update your spinner. This change also makes it easier to customize the spinner. + +See [this discussion](https://discuss.flarum.org/d/26994-beta16-using-the-new-loading-spinner) for more information. + +### classList util + +Ever wrote messy code trying to put together a list of classes for some component? Well, no longer! The [clsx library](https://www.npmjs.com/package/clsx) is now available as the `flarum/common/utils/classList` util. + +### User List + +An extensible user list has been added to the admin dashboard. In future releases, we hope to extract a generic model table component that can be used to list any model in the admin dashboard. + +See [the source code](https://github.com/flarum/core/blob/master/js/src/admin/components/UserListPage.tsx#L41) for a list of methods to extend, and examples of how columns should look like (can be added by extending the `columns` method and adding items to the [ItemList](frontend.md)). + +### Miscellaneous + +- Components should now call `super` for ALL Mithril lifecycle methods they define. Before, this was only needed for `oninit`, `onbeforeupdate`, and `oncreate`. Now, it is also needed in `onupdate`, `onbeforeremove`, and `onremove`. See [this GitHub issue](https://github.com/flarum/core/issues/2446) for information on why this change was made. +- The `flarum/common/utils/insertText` and `flarum/common/utils/styleSelectedText` utils have been moved to core from `flarum/markdown`. See `flarum/markdown` for an example of usage. +- The `extend` and `override` utils can now modify several methods at once by passing in an array of method names instead of a single method name string as the second argument. This is useful for extending the `oncreate` and `onupdate` methods at once. +- The `EditUserModal` component is no longer available through the `flarum/forum` namespace, it has been moved to `flarum/common`. Imports should be adjusted. +- The `Model` and `Route` JS extenders have been removed for now. There aren't currently used in any extensions that we know of. We will be reintroducing JS extenders during v1.x releases. +- The `Search` component can now be used with the `SearchState` state class. Previously, `SearchState` was missing the `getInitialSearch` method expected by the `Search` component. + +## Backend + +### Filesystem Extenders + +In this release, we refactored our use of the filesystem to more consistently use [Laravel's filesystem API](https://laravel.com/docs/8.x/filesystem). Extensions can now declare new disks, more easily use core's `flarum-assets` and `flarum-avatars` disks, and create their own storage drivers, enabling CDN and cloud storage support. + +### Compat and Closure Extenders + +In early Flarum versions, the `extend.php` file allowed arbitrary functions that allowed execution of arbitrary code one extension boot. For example: + +```php +return [ + // other extenders + function (Dispatcher $events) { + $events->subscribe(Listener\FilterDiscussionListByTags::class); + $events->subscribe(Listener\FilterPostsQueryByTag::class); + $events->subscribe(Listener\UpdateTagMetadata::class); + } +]; +``` + +This approach was difficult to maintain and provide a well-tested public API for, frequently resolved classes early (breaking all sorts of things), and was not very descriptive. With the extender API completed in beta 16, this approach is no longer necessary. Support for these closures has been removed in this stable version. + +One type of functionality for which the extender replacement isn't obvious is container bindings ([e.g. flarum/pusher](https://github.com/flarum/pusher/blob/v0.1.0-beta.14/extend.php#L33-L49)). This can be done with via the service provider extender (e.g. [a newer version of flarum/pusher](https://github.com/flarum/pusher/blob/master/extend.php#L40-L41)). + +If you are unsure about which extenders should be used to replace your use of callbacks in `extend.php`, or are not sure that such an extender exists, please comment so below or reach out! We're in the final stages of finishing up the extender API, so now is the time to comment. + +### Scheduled Commands + +The [fof/console](https://github.com/FriendsOfFlarum/console) library has been a popular way to schedule commands (e.g. for publishing scheduled posts, running DB-heavy operations, etc) for several release. In Flarum 1.0, this functionality has been brought into core's `Console` extender. See our [console extension documentation](console.md) for more information on how to create schedule commands, and our [console user documentation](../console.md) for more information on how to run scheduled commands. + +### Eager Loading Extender + +As part of solving [N+1 Query issues](https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/) in some [Flarum API endpoints](https://github.com/flarum/core/issues/2637), we have introduced a `load` method on the `ApiController` extender that allows you to indicate relations that should be eager loaded. + +This should be done if you know a relation will always be included, or will always be referenced by controller / permission logic. For example, we will always need the tags of a discussion to check what permissions a user has on that discussion, so we should eager load the discussion's `tags` relationship. For example: + +```php +return [ + // other extenders + (new Extend\ApiController(FlarumController\ListDiscussionsController::class)) + ->addInclude(['tags', 'tags.state', 'tags.parent']) + ->load('tags'), +]; +``` + +### RequestUtil + +The `Flarum\Http\RequestUtil`'s `getActor` and `withActor` should be used for getting/setting the actor (user) on requests. `$request->getAttribute('actor')` and `$request->withAttribute('actor')` are deprecated, and will be removed in v2.0. + +### Miscellaneous + +- The `Formatter` extender now has an `unparse` method that allows modifying XML before unparsing content. +- All route names must now be unique. In beta 16, uniqueness was enforced per-method; now, it is mandatory for all routes. +- API requests sent through `Flarum\Api\Client` now run through middleware, including `ThrottleApi`. This means that it is now possible to throttle login/registration calls. +- In beta 16, registering custom [searchers](search.md) was broken. It has been fixed in stable. +- The `post_likes` table in the [flarum/likes](https://github.com/flarum/likes) extension now logs the timestamp when likes were created. This isn't used in the extension, but could be used in other extensions for analytics. +- The `help` attribute of [admin settings](admin.md) no longer disappears on click. +- The `generate:migration` console command has been removed. The [Flarum CLI](https://discuss.flarum.org/d/26525-rfc-flarum-cli-alpha) should be used instead. +- The `GambitManager` util class is now considered internal API, and should not be used directly by extensions. +- The `session` attribute is no longer available on the `User` class. This caused issues with queue drivers, and was not conceptually correct (a user can have multiple sessions). The current session is still available via the `$request` instance. +- The `app`, `base_path`, `public_path`, `storage_path`, and `event` global helpers have been restored, but deprecated perpetually. These exist in case Laravel packages need them; they **should not** be used directly by Flarum extension code. The `flarum/laravel-helpers` package has been abandoned. +- The following deprecated features from beta 16 have been removed: + - The `TextEditor`, `TextEditorButton`, and `SuperTextarea` components are no longer exported through the `flarum/forum` namespace, but through `flarum/common` (with the exception of `SuperTextarea`, which has been replaced with `flarum/common/utils/BasicEditorDriver`). + - Support for `Symfony\Component\Translation\TranslatorInterface` has been removed, `Symfony\Contracts\Translation\TranslatorInterface` should be used instead. + - All backwards compatibility layers for the [beta 16 access token refactors](update-b16.md#access-token-and-authentication-changes) have been removed + - The `GetModelIsPrivate` event has been removed. The `ModelPrivate` extender should be used instead. + - The `Searching` (for both `User` and `Discussion` models), `ConfigureAbstractGambits`, `ConfigureDiscussionGambits`, and `ConfigureUserGambits` events have been removed. The `SimpleFlarumSearch` extender should be used instead. + - The `ConfigurePostsQuery` event has been removed. The `Filter` extender should be used instead. + - The `ApiSerializer` extender's `mutate` method has been removed. The same class's `attributes` method should be used instead. + - The `SearchCriteria` and `SearchResults` util classes have been removed. `Flarum\Query\QueryCriteria` and `Flarum\Query\QueryResults` should be used instead. + - The `pattern` property of `AbstractRegexGambit` has been removed; the `getGambitPattern` method is now a required abstract method. + - The `AbstractSearch` util class has been removed. `Flarum\Search\SearchState` and `Flarum\Filter\FilterState` should be used instead. + - The `CheckingPassword` event has been removed, the `Auth` extender should be used instead. + +## Tags Extension Changes + +As mentioned above, [tag scopable permissions](#permissions-changes) can now be explicitly declared. + +We've also made several big refactors to significantly improve tags performance. + +Firstly, the [Tag](https://github.com/flarum/tags/blob/d093ca777ba81f826157522c96680717d3a90e24/src/Tag.php#L38-L38) model's static `getIdsWhereCan` and `getIdsWhereCannot` methods have been removed. These methods scaled horribly on forums with many tags, sometimes adding several seconds to response time. + +These methods have been replaced with a `whereHasPermission` [Eloquent dynamic scope](https://laravel.com/docs/8.x/eloquent#dynamic-scopes) that returns a query. For example: + +`Tag::whereHasPermission($actor, 'viewDiscussions)`. + +That query can then be used in other DB queries, or further constricted to retrieve individual tags. + +Secondly, we no longer load in all tags as part of the initial payload. The initial payload contains all top-level primary tags, and the top 3 secondary tags. Other tags are loaded in as needed. Future releases will paginate secondary tags. This should enable forums to have thousands of secondary tags without significant performance impacts. These changes mean that extensions should not assume that all tags are available in the model store. + +## Testing Library Changes + +- Bundled extensions will not be automatically enabled; all enabled extensions must be specified in that test case. +- `setting` and `config` methods have been added that allow configuring settings and config.php values before the tested application boots. See [the testing docs](testing.md) for more information. +- The `php flarum test:setup` command will now drop the existing test DB tables before creating the database. This means that you can run `php flarum test:setup` to ensure a clean database without needing to go into the database and drop tables manually. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md new file mode 100644 index 000000000..cd81ab68d --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md @@ -0,0 +1,139 @@ +# Cập nhật 1.x + +:::tip + +Nếu bạn cần sự trợ giúp về những thay đổi mới này, vui lòng tạo cuộc thảo luận trên [cộng đồng Flarum](https://discuss.flarum.org/t/extensibility) hoặc [Discord](https://flarum.org/discord/). + +::: + +## 1.7 + +### Frontend + +- Frontend extenders similar to the backend have been added, we highly recommend using them instead of the old method (https://docs.flarum.org/extend/models#adding-new-models-1), (https://docs.flarum.org/extend/routes#frontend-routes). +- There is a new tag selection component (https://github.com/flarum/framework/blob/360a2ba1d886df3fc6d326be932c5431ee9df8cf/extensions/tags/js/src/common/components/TagSelectionModal.tsx). + +### Backend + +- Support for php 8.2, deprecations are still thrown by some packages, the testing workflow has been updated to ignore deprecations on 8.2 +- The `/api` endpoint now contains the actor as an included relationship. +- The `Model::dateAttribute($attribute)` extender is deprecated, use `Model::cast($attribute, 'datetime')` instead. + +### Tooling + +- New `phpstan` package to run static code analysis on your extensions for code safety (https://docs.flarum.org/extend/static-code-analysis). +- New `jest-config` package to run frontend unit and component tests (https://docs.flarum.org/extend/testing). + +## 1.6 Changes + +### Backend + +- Added customizable session drivers through the `Session` extender. + +## 1.5 Changes + +### Frontend + +- More portions of the frontend are now written in TypeScript, providing a better extension development experience. +- Modals can be used in stacks, allowing for multiple modals to be open at once. This is useful for modals that open other modals: `app.modal.show(ModalComponent, { attrs }, true)`. + +### Backend + +- There is a new `createTableIfNotExists` migration helper, which can be used to create tables only if they don't already exist. + +## 1.4 Changes + +No developer-facing changes were made in Flarum v1.4. + +## 1.3 Changes + +Flarum v1.3 included mostly QoL improvements. Below are listed note worthy changes for extension developers: + +### Frontend + +- More portions of the frontend are now written in TypeScript, providing a better extension development experience. +- Frontend errors will no longer cause the forum to crash into a NoJs page. The extension will fail to execute its frontend code (initializer) and display an error to the admin through an alert, and to all users through the console. The frontend will continue to execute without the extension's frontend changes. +- The markdown toolbar can now be used on the admin side. + +### Backend + +- Calculation of the `number` attribute on `posts` has changed and no longer relies on the discussion model's `post_number_index` attribute which is now deprecated and will be removed in 2.0 +- Extension event listeners are now added after core even listeners, this should generally cause no changes in behavior. + +### Tooling + +- The backend tests workflow now automatically fails tests if there are any PHP warnings and notices. + +## 1.2 Changes + +Flarum v1.2 included quite a few bugfixes, internal refactors, and new features. The following recaps the most important changes for extension developers: + +### Frontend + +- Flarum core now passes TypeScript type checking (on the portion written in TypeScript). Additionally, major portions of the frontend (models, the application instance, and others) are now written in TypeScript. These changes should make it much easier and more fruitful to write extensions in TypeScript. +- Instead of directly using Less variables in CSS code, core now uses CSS variables. For the most part, we've just created CSS variables and set their values to the Less variables. This should make theming and customizing CSS a lot easier. https://github.com/flarum/core/pull/3146. +- Dropdowns can now be lazy-drawn to improve performance. You can do this by setting the lazy draw attr to "true". https://github.com/flarum/core/pull/2925. +- [Textarea-type settings](https://github.com/flarum/core/pull/3141) are now supported through the `app.extensionData.registerSetting` util. +- You can now use Webpack 5 to bundle your extension's code. This will offer minor bundle size improvements. +- A new `flarum/common/components/ColorPreviewInput` component [has been added](https://github.com/flarum/core/pull/3140). It can be used directly, or through the `color-preview` type when registered via `app.extensionData.registerSetting`. +- Extensions can now [modify the minimum search length](https://github.com/flarum/core/pull/3130) of the `Search` component. +- The following components are now extensible: + - The "colors" part of the Appearance page in the admin dashboard: https://github.com/flarum/core/pull/3186 + - The `StatusWidget` dropdown in the admin dashboard: https://github.com/flarum/core/pull/3189 + - `primaryControls` in the notification list: https://github.com/flarum/core/pull/3204 +- Extensions now have finer control over positioning when adding elements to the DiscussionPage sidebar items: https://github.com/flarum/core/pull/3165 +- + +### Backend + +- An [extender for settings defaults](https://github.com/flarum/core/pull/3127) has been added. This should be used instead of the `addSettings` migration helper, which has been deprecated. +- You can now [generate Less variables from setting values](https://github.com/flarum/core/pull/3011) via the `Settings` extender. +- Extensions can now [override/supplement blade template namespaces](https://github.com/flarum/core/pull/3167) through the `View` extender, meaning custom blade templates can be used instead of the default ones added by core or extensions. +- You can now define [custom Less functions through PHP](https://github.com/flarum/core/pull/3190), allowing you to use some backend logic in your Less theming. +- Extensions can now create [custom page title drivers](https://github.com/flarum/core/pull/3109/files) for titles in server-returned HTML. +- Custom logic can now be used when [deciding which relations to eager-load](https://github.com/flarum/core/pull/3116). +- Events [are now dispatched](https://github.com/flarum/core/pull/3203) for the `Notification\Read` and `Notification\ReadAll` events. +- An `ImageManager` instance is now [bound into the container](https://github.com/flarum/core/pull/3195), and can be configured to use either the `gd` or `imagick` backing drivers via the `"intervention.driver"` key in `config.php`. +- User IP addresses are now passed to the [API Client](https://github.com/flarum/core/pull/3124). +- A custom revision versioner implentation [can be set via container bindings](https://github.com/flarum/core/pull/3183) to customize how asset versions are named. +- A SlugManager instance [is now available](https://github.com/flarum/core/pull/3194) in blade templates via the `slugManager` variable. + +### Misc + +- Translations now support the `zero`, `one`, `two`, `few`, and `many` localized plural rules for `plural` ICU MessageFormat translations. This was done through the [`Intl.PluralRules` helper](https://github.com/flarum/core/issues/3072). +- Translations are now used for page titles, so that the format can be customized via language packs or [Linguist](https://discuss.flarum.org/d/7026-linguist-customize-translations-with-ease): https://github.com/flarum/core/pull/3077, https://github.com/flarum/core/pull/3228 +- API endpoints for retrieving single groups, as well as support for filtering groups on the plural get endpoint, [have been added](https://github.com/flarum/core/pull/3084). + + +### Tooling + + +- The `flarum-cli infra` command can now be used to update or enable various infrastructure features. You can now add the following to your extension in just one command: + - TypeScript + - Prettier for JS/TS formatting + - Backend testing with PHPUnit + - Code formatting with StyleCI + - EditorConfig support + - GitHub actions for automating testing, linting, type checking, and building. +- You can also exclude any files from these updates by adding their relative path to the "extra.flarum-cli" key's array in your extension's `composer.json` file. For example, if you wanted to exclude your tsconfig file from any updates by the infra system, the "extra.flarum-cli" key's value should be `["js/tsconfig.json"]`. +- The `flarum-cli audit infra` can be used to check that all infra modules your extension uses are up to date. The `--fix` flag can be used to automatically fix any issues, which has essentially the same effect as running `flarum-cli infra` for each outdated module. +- All `flarum-cli` commands can now be run with a `--no-interaction` flag to prevent prompts. Defaults will be used when possible, and errors will be thrown if a prompt is needed and there is no default. +- Frontend GH actions now support type-checking, as well as type coverage reports. + +## 1.1 Changes + +Flarum version 1.1 mostly focuses on bugfixes and quality-of-life improvements following our stable release earlier this year. These are mainly user-facing and internal infrastructure changes, so extensions are not significantly affected. + +### Frontend + +- Flarum now has an organization-wide prettier config package under [`@flarum/prettier-config`](https://github.com/flarum/prettier-config). +- Most custom (setting or data based) coloring in core is now done via [CSS custom properties](https://github.com/flarum/core/pull/3001). +- Typehinting for Flarum's globals are now [supported in extensions](https://github.com/flarum/core/pull/2992). +- You can now pass extra attrs to the `Select` component, and they will be [passed through to the DOM](https://github.com/flarum/core/pull/2959). +- The `DiscussionPage` component is now organized [as an item list](https://github.com/flarum/core/pull/3004), so it's easier for extensions to change its content. +- Extensions [can now edit](https://github.com/flarum/core/pull/2935) the `page` parameter of `PaginatedListState`. + +### Backend + +- Flarum now comes with a [Preload extender](https://github.com/flarum/core/pull/3057) for preloading any custom frontend assets. +- A new [Theme](https://github.com/flarum/core/pull/3008) extender now allows overriding Less files and internal imports. This allows themes to more easily completely replace Less modules. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md new file mode 100644 index 000000000..8266e4559 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md @@ -0,0 +1,53 @@ +# Cập nhật cho Beta 10 + +Beta 10 further solidifies the core architecture, offering new extenders as a stable, use-case-driven API for extending Flarum's core. A few small changes may necessitate updates to your extensions to make them compatible with Beta 10. These are detailed below. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Breaking Changes + +- The `Flarum\Event\GetDisplayName` class has been moved to `Flarum\User\Event\GetDisplayName`. +- The `Flarum\Http\Exception\ForbiddenException` has been removed. Use `Flarum\User\Exception\PermissionDeniedException` instead. +- The `assertGuest()` method of the `Flarum\User\AssertPermissionTrait` has been removed without replacement. +- Old error handling middleware and exception handler classes were removed (see "New Features" for more details): + - `Flarum\Api\Middleware\HandleErrors` + - `Flarum\Http\Middleware\HandleErrorsWithView` + - `Flarum\Http\Middleware\HandleErrorsWithWhoops` + - `Flarum\Api\ErrorHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + - `Flarum\Api\ExceptionHandler\FloodingExceptionHandler` + - `Flarum\Api\ExceptionHandler\IlluminateValidationExceptionHandler` + - `Flarum\Api\ExceptionHandler\InvalidAccessTokenExceptionHandler` + - `Flarum\Api\ExceptionHandler\InvalidConfirmationTokenExceptionHandler` + - `Flarum\Api\ExceptionHandler\MethodNotAllowedExceptionHandler` + - `Flarum\Api\ExceptionHandler\ModelNotFoundExceptionHandler` + - `Flarum\Api\ExceptionHandler\PermissionDeniedExceptionHandler` + - `Flarum\Api\ExceptionHandler\RouteNotFoundExceptionHandler` + - `Flarum\Api\ExceptionHandler\TokenMismatchExceptionHandler` + - `Flarum\Api\ExceptionHandler\ValidationExceptionHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + +## Recommendations + +- We tweaked the [recommended flarum/core version constraints for extensions](start.md#composer-json). We now recommend you mark your extension as compatible with the current and the upcoming beta release. (For beta.10, that would be any beta.10.x and beta.11.x version.) The core team will strive to make this work well by deprecating features before removing them. More details on this change in [this pull request](https://github.com/flarum/docs/pull/75). + +## New Features + +- New, extensible **error handling** stack in the `Flarum\Foundation\ErrorHandling` namespace: The `Registry` maps exceptions to "types" and HTTP status codes, `HttpFormatter` instances turn them into HTTP responses. Finally, `Reporter` instances are notified about unknown exceptions. + - You can build custom exception classes that will abort the current request (or console command). If they have semantic meaning to your application, they should implement the `Flarum\Foundation\KnownError` interface, which exposes a "type" that is used to render pretty error pages or dedicated error messages. + - More consistent use of HTTP 401 and 403 status codes. HTTP 401 should be used when logging in (i.e. authenticating) could make a difference; HTTP 403 is reserved for requests that fail because the already authenticated user is lacking permissions to do something. + - The `assertRegistered()` and `assertPermission()` methods of the `Flarum\User\AssertPermissionTrait` trait have been changed to match above semantics. See [this pull request](https://github.com/flarum/core/pull/1854) for more details. + - Error views are now determined based on error "type", not on status code (see [bdac88b](https://github.com/flarum/core/commit/bdac88b5733643b9c5dabae9e09a64d9f6e41d58)) +- **Queue support**: This release incorporates Laravel's illuminate/queue package, which allows offloading long-running tasks (such as email sending or regular cleanup jobs) onto a dedicated worker process. These changes are mostly under the hood, the next release(s) will start using the queue system for sending emails. By default, Flarum will use the "sync" queue driver, which executes queued tasks immediately. This is far from ideal and mostly guarantees a hassle-free setups. Production-grade Flarum installs are expected to upgrade to a more full-featured queue adapter. +- The `Flarum\Extend\LanguagePack` now accepts an optional path in its constructor. That way, language packs can store their locales in a different directory if they want to. +- The `formatContent()` method of `Flarum\Post\CommentPost` can now be called without an HTTP request instance, e.g. when rendering a post in an email template. + +## Deprecations + +- **Reminder**: In previous versions of Flarum, an extensions' main file was named `bootstrap.php`. This name will no longer be supported in the stable 0.1 release. Make sure your extension uses the name `extend.php`. +- Laravel's global string and array helpers (e.g. `str_contains()` and `array_only()`) are deprecated in favor of their class based alternatives (`Illuminate\Support\Str::contains()` and `Illuminate\Support\Arr::only()`). See the [announcement](https://laravel-news.com/laravel-5-8-deprecates-string-and-array-helpers) and [pull request](https://github.com/laravel/framework/pull/26898) for more information. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md new file mode 100644 index 000000000..6655a213c --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md @@ -0,0 +1,34 @@ +# Cập nhật cho Beta 12 + +Beta 12 packs several new features for extension developers, but also continues our cleanup efforts which results in a few changes, so please read this guide carefully to find out whether your extensions are affected. We invested extra effort to introduce new functionality in a backward-compatible manner or first deprecate functionality before it will be removed in the next release, in line with our [versioning recommendations](start.md#composer-json). + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Deprecations / Upcoming breaking changes + +- **Reminder**: In previous versions of Flarum, an extensions' main file was named `bootstrap.php`. This name will no longer be supported in the stable 0.1 release. Make sure your extension uses the name `extend.php`. +- PHP 7.1 support will be dropped in beta.13. +- Using library classes from the `Zend` namespace is now deprecated and will be removed in beta.13. Use the `Laminas` namespace instead. See [PR #1963](https://github.com/flarum/core/pull/1963). +- The `Flarum\Util\Str::slug()` method has been deprecated. Use `Illuminate\Support\Str::slug()` instead. +- The `Flarum\Event\ConfigureMiddleware` has been deprecated. We finally have a [proper replacement](middleware.md) - see "New Features" below. Therefore, it will be removed in beta.13. +- If you implement the `Flarum\Mail\DriverInterface`: + - Returning a plain array of field names from the `availableSettings()` method is deprecated, but still supported. It must now return an array of field names mapping to their type. See [the inline documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L25-L32) for more details. + - Implement the `validate()` method that will be required in beta.13. See [its documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L34-L48). + - Implement the `canSend()` method that will be required in beta.13. See [its documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L50-L54). + +## New Features + +- New **PHP extenders**: + - `Flarum\Extend\Middleware` offers methods for adding, removing or replacing middleware in our three middleware stacks (api, forum, admin). We also added [documentation](middleware.md) for this feature. + - `Flarum\Extend\ErrorHandling` lets you configure status codes and other aspects of our error handling stack depending on error types or exception classes. +- **JavaScript**: + - The `flarum/components/Select` component now supports a `disabled` prop. See [PR #1978](https://github.com/flarum/core/pull/1978). + +## Other changes / Recommendations + +- The `TextFormatter` library has been updated to (at least) version 2.3.6. If you are using it (likely through our own `Flarum\Formatter\Formatter` class), we recommend scanning [the library's changelog](https://github.com/s9e/TextFormatter/blob/2.3.6/CHANGELOG.md). +- The JS `slug()` helper from the `flarum/utils/string` module should only be used to *suggest* slugs to users, not enforce them. It does not employ any sophisticated transliteration logic like its PHP counterpart. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md new file mode 100644 index 000000000..82e2744ff --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md @@ -0,0 +1,40 @@ +# Cập nhật cho Beta 13 + +Beta 13 ships with several new extenders to simplify building and maintaining extensions. We do our best to create backward compatibility changes. We recommend changing to new Extenders as soon as they are available. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Breaking Changes + +- Dropped support for PHP 7.1. +- Classes from the `Zend` namespace are now removed. Use the `Laminas` namespace instead. See [PR #1963](https://github.com/flarum/core/pull/1963). +- The `Flarum\Util\Str::slug()` method has been removed including the class. Use `Illuminate\Support\Str::slug()` instead. +- The `Flarum\Event\ConfigureMiddleware` has been removed. Use the [proper replacement](middleware.md). +- Several events used in Event Listeners have been removed, use their [replacement extender](start.md#extenders) instead. +- The LanguagePack extender only loads keys from extensions that are enabled. The translations loaded are based on the yaml files matching the [i18n namespace](i18n.md#appendix-a-standard-key-format). +- All notifications are now sent through the queue; without a queue driver they will run as usual. +- The implementation of avatar upload changed, we're [no longer storing files temporarily on disk](https://github.com/flarum/core/pull/2117). +- The SES mail driver [has been removed](https://github.com/flarum/core/pull/2011). +- Mail driver backward compatibility from beta 12 has been removed, use the new Mail extender or implement the [modified interface](https://github.com/flarum/core/blob/master/src/Mail/DriverInterface.php). + +## Recommendations + +- Beta 14 will ship with a rewrite in the frontend (javascript). If you're building for that release, make sure to follow our [progress](https://github.com/flarum/core/pull/2126). + +## New Features + +- A ton of new extenders: + - [Middleware extender](https://github.com/flarum/core/pull/2017) + - [Console extender](https://github.com/flarum/core/pull/2057) + - [CSRF extender](https://github.com/flarum/core/pull/2095) + - [Event extender](https://github.com/flarum/core/pull/2097) + - [Mail extender](https://github.com/flarum/core/pull/2012) + - [Model extender](https://github.com/flarum/core/pull/2100) + +## Deprecations + +- Several events [have been marked deprecated](https://github.com/flarum/core/commit/4efdd2a4f2458c8703aae654f95c6958e3f7b60b) to be removed in beta 14. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md new file mode 100644 index 000000000..7144ade80 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md @@ -0,0 +1,757 @@ +# Cập nhật cho Beta 14 + +This release brings a large chunk of breaking changes - hopefully the last chunk of this size before our stable release. In order to prepare the codebase for the upcoming stable release, we decided it was time to modernize / upgrade / exchange some of the underlying JavaScript libraries that are used in the frontend. Due to the nature and size of these upgrades, we have to pass on some of the breaking changes to you, our extension developers. + +On the bright side, this overdue upgrade brings us closer to the conventions of best practices of [Mithril.js](https://mithril.js.org/), the mini-framework used for Flarum's UI. Mithril's 2.0 release sports a more consistent component interface, which should be a solid foundation for years to come. Where possible, we replicated old APIs, to ease the upgrade and give you time to do the full transition. Quite a few breaking changes remain, though - read more below. + +:::tip + +If you need help with the upgrade, our friendly community will gladly help you out either [on the forum](https://discuss.flarum.org/t/extensibility) or [in chat](https://flarum.org/chat/). + +::: + +To ease the process, we've clearly separated the changes to the [frontend (JS)](#frontend-javascript) from those in the [backend (PHP)](#backend-php) below. If your extension does not change the UI, consider yourself lucky. :-) + +A [summary of the frontend changes](#required-frontend-changes-recap) is available towards the end of this guide. + +## Frontend (JavaScript) + +### Mithril 2.0: Concepts + +Most breaking changes required by beta 14 are prompted by changes in Mithril 2. [Mithril's upgrade guide](https://mithril.js.org/migration-v02x.html) is an extremely useful resource, and should be consulted for more detailed information. A few key changes are explained below: + +#### props -> attrs; initProps -> initAttrs + +Props passed into component are now referred to as `attrs`, and can be accessed via `this.attrs` where you would prior use `this.props`. This was done to be closer to Mithril's preferred terminology. We have provided a temporary backwards compatibility layer for `this.props`, but recommend using `this.attrs`. + +Accordingly, `initProps` has been replaced with `initAttrs`, with a similar BC layer. + +#### m.prop -> `flarum/utils/Stream` + +Mithril streams, which were available via `m.prop` in Mithril 0.2, are now available via `flarum/utils/Stream`. `m.prop` will still work for now due to a temporary BC layer. + +#### m.withAttr -> withAttr + +The `m.withAttr` util has been removed from Mithril. We have provided `flarum/utils/withAttr`, which does the same thing. A temporary BC layer has been added for `m.withAttr`. + +#### Lifecycle Hooks + +In mithril 0.2, we had 2 "lifecycle hooks": + +`init`, an unofficial hook which ran when the component instance was initialized. + +`config`, which ran when components were created, and on every redraw. + + +Mithril 2 has the following hooks; each of which take `vnode` as an argument: + +- `oninit` +- `oncreate` +- `onbeforeupdate` +- `onupdate` +- `onbeforeremove` +- `onremove` + +Please note that if your component is extending Flarum's helper `Component` class, you must call `super.METHOD(vnode)` if using `oninit`, `oncreate`, and `onbeforeupdate`. + +More information about what each of these do can be found [in Mithril's documentation](https://mithril.js.org/lifecycle-methods.html). + +A trivial example of how the old methods map to the new is: + +```js +class OldMithrilComponent extends Component { + init() { + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + config(element, isInitialized) { + console.log('Code to run on every redraw AND when the element is first attached'); + + if (isInitialized) return; + + console.log('Code to execute only once when components are first created and attached to the DOM'); + + context.onunload = () => { + console.log('Code to run when the component is removed from the DOM'); + } + } + + view() { + // In mithril 0, you could skip redrawing a component (or part of a component) by returning a subtree retain directive. + // See https://mithril.js.org/archive/v0.2.5/mithril.render.html#subtree-directives + // dontRedraw is a substitute for logic; usually, this is used together with SubtreeRetainer. + if (dontRedraw()) return { subtree: 'retain' }; + + return

Hello World!

; + } +} + +class NewMithrilComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + oncreate(vnode) { + super.oncreate(vnode); + + console.log('Code to run when components are first created and attached to the DOM'); + } + + onbeforeupdate(vnode, oldVnode) { + super.onbeforeupdate(vnode); + + console.log('Code to run BEFORE diffing / redrawing components on every redraw'); + + // In mithril 2, if we want to skip diffing / redrawing a component, we return "false" in its onbeforeupdate lifecycle hook. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeupdate + // This is also typically used with SubtreeRetainer. + if (dontRedraw()) return false; + } + + onupdate(vnode) { + // Unlike config, this does NOT run when components are first attached. + // Some code might need to be replicated between oncreate and onupdate. + console.log('Code to run on every redraw AFTER the DOM is updated.'); + } + + onbeforeremove(vnode) { + // This is run before components are removed from the DOM. + // If a promise is returned, the DOM element will only be removed when the + // promise completes. It is only called on the top-level component that has + // been removed. It has no equivalent in Mithril 0.2. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeremove + return Promise.resolve(); + } + + onremove(vnode) { + console.log('Code to run when the component is removed from the DOM'); + } +} +``` + +#### Children vs Text Nodes + +In Mithril 0.2, every child of a vnode is another vnode, stored in `vnode.children`. For Mithril 2, as a performance optimization, vnodes with a single text child now store that text directly in `vnode.text`. For developers, that means that `vnode.children` might not always contain the results needed. Luckily, text being stored in `vnode.text` vs `vnode.children` will be the same each time for a given component, but developers should be aware that at times, they might need to use `vnode.text` and not `vnode.children`. + +Please see [the mithril documentation](https://mithril.js.org/vnodes.html#structure) for more information on vnode structure. + +#### Routing API + +Mithril 2 introduces a few changes in the routing API. Most of these are quite simple: + +- `m.route()` to get the current route has been replaced by `m.route.get()` +- `m.route(NEW_ROUTE)` to set a new route has been replaced by `m.route.set(NEW_ROUTE)` +- When registering new routes, a component class should be provided, not a component instance. + +For example: + +```js +// Mithril 0.2 +app.routes.new_page = { path: '/new', component: NewPage.component() } + +// Mithril 2.0 +app.routes.new_page = { path: '/new', component: NewPage } +``` + +Additionally, the preferred way of defining an internal (doesn't refresh the page when clicked) link has been changed. The `Link` component should be used instead. + +```js +// Mithril 0.2 +
Link Content + +// Mithril 2 +import Link from 'flarum/components/Link'; + +Link Content +``` + +You can also use `Link` to define external links, which will just render as plain `Children` html links. + +For a full list of routing-related changes, please see [the mithril documentation](https://mithril.js.org/migration-v02x.html). + +#### Redraw API + +Mithril 2 introduces a few changes in the redraw API. Most of these are quite simple: + +- Instead of `m.redraw(true)` for synchronous redraws, use `m.redraw.sync()` +- Instead of `m.lazyRedraw()`, use `m.redraw()` + +Remember that Mithril automatically triggers a redraw after DOM event handlers. The API for preventing a redraw has also changed: + +```js +// Mithril 0.2 + + +// Mithril 2 + +``` + +#### AJAX + +The `data` parameter of `m.request({...})` has been split up into `body` and `params`. + +For examples and other AJAX changes, see [the mithril documentation](https://mithril.js.org/migration-v02x.html#mrequest). + +#### Promises + +`m.deferred` has been removed, native promises should be used instead. For instance: + +```js +// Mithril 0.2 +const deferred = m.deferred(); + +app.store.find('posts').then(result => deferred.resolve(result)); + +return deferred.promise; + +// Mithril 2 +return app.store.find('posts'); +``` + +#### Component instances should not be stored + +Due to optimizations in Mithril's redrawing algorithms, [component instances should not be stored](https://mithril.js.org/components.html#define-components-statically,-call-them-dynamically). + +So whereas before, you might have done something like: + +```js +class ChildComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return

{this.counter}

; + } +} +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.child = new ChildComponent(); + } + + view() { + return ( +
+ + {this.child.render()} +
+ ) + } +} +``` + +That will no longer work. In fact; the Component class no longer has a render method. + +Instead, any data needed by a child component that is modified by a parent component should be passed in as an attr. For instance: + +```js +class ChildComponent extends Component { + view() { + return

{this.attrs.counter}

; + } +} + +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return ( +
+ + +
+ ) + } +} +``` + +For more complex components, this might require some reorganization of code. For instance, let's say you have data that can be modified by several unrelated components. In this case, it might be preferable to create a POJO "state instance' for this data. These states are similar to "service" singletons used in Angular and Ember. For instance: + +```js +class Counter { + constructor() { + this._counter = 0; + } + + increaseCounter() { + this._counter += 1; + } + + getCount() { + return this._counter; + } +} + +app.counter = new Counter(); + +extend(HeaderSecondary.prototype, 'items', function(items) { + items.add('counterDisplay', +
+

Counter: {app.counter.getCount()}

+
+ ); +}) + +extend(HeaderPrimary.prototype, 'items', function(items) { + items.add('counterButton', +
+ +
+ ); +}) +``` + +This "state pattern" can be found throughout core. Some non-trivial examples are: + +- PageState +- SearchState and GlobalSearchState +- NotificationListState +- DiscussionListState + +### Changes in Core + +#### Modals + +Previously, modals could be opened by providing a `Modal` component instance: + +```js +app.modal.show(new LoginModal(identification: 'prefilledUsername')); +``` + +Since we don't store component instances anymore, we pass in the component class and any attrs separately. + +```js +app.modal.show(LoginModal, {identification: 'prefilledUsername'}); +``` + +The `show` and `close` methods are still available through `app.modal`, but `app.modal` now points to an instance of `ModalManagerState`, not of the `ModalManager` component. Any modifications by extensions should accordingly be done to `ModalManagerState`. + +#### Alerts + +Previously, alerts could be opened by providing an `Alert` component instance: + +```js +app.alerts.show(new Alert(type: 'success', children: 'Hello, this is a success alert!')); +``` + +Since we don't store component instances anymore, we pass in a component class, attrs, children separately. The `show` method has 3 overloads: + +```js +app.alerts.show('Hello, this is a success alert!'); +app.alerts.show({type: 'success'}, 'Hello, this is a success alert!'); +app.alerts.show(Alert, {type: 'success'}, 'Hello, this is a success alert!'); +``` + +Additionally, the `show` method now returns a unique key, which can then be passed into the `dismiss` method to dismiss that particular alert. This replaces the old method of passing the alert instance itself to `dismiss`. + +The `show`, `dismiss`, and `clear` methods are still available through `app.alerts`, but `app.alerts` now points to an instance of `AlertManagerState`, not of the `AlertManager` component. Any modifications by extensions should accordingly be done to `AlertManagerState`. + +#### Composer + +Since we don't store a component instances anymore, a number of util methods from `Composer`, `ComposerBody` (and it's subclasses), and `TextEditor` have been moved onto `ComposerState`. + +For `forum/components/Composer`, `isFullScreen`, `load`, `clear`, `show`, `hide`, `close`, `minimize`, `fullScreen`, and `exitFullScreen` have been moved to `forum/states/ComposerState`. They all remain accessible via `app.composer.METHOD` + +A `bodyMatches` method has been added to `forum/states/ComposerState`, letting you check whether a certain subclass of `ComposerBody` is currently open. + +Various input fields are now stored as [Mithril Streams](https://mithril.js.org/stream.html) in `app.composer.fields`. For instance, to get the current composer content, you could use `app.composer.fields.content()`. Previously, it was available on `app.composer.component.content()`. **This is a convention that `ComposerBody` subclasses that add inputs should follow.** + +`app.composer.component` is no longer available. + +- Instead of `app.composer.component instanceof X`, use `app.composer.bodyMatches(X)`. +- Instead of `app.composer.component.props`, use `app.composer.body.attrs`. +- Instead of `app.composer.component.editor`, use `app.composer.editor`. + +For `forum/components/TextEditor`, the `setValue`, `moveCursorTo`, `getSelectionRange`, `insertAtCursor`, `insertAt`, `insertBetween`, `replaceBeforeCursor`, `insertBetween` methods have been moved to `forum/components/SuperTextarea`. + +Also for `forum/components/TextEditor`, `this.disabled` is no longer used; `disabled` is passed in as an attr instead. It may be accessed externally via `app.composer.body.attrs.disabled`. + +Similarly to Modals and Alerts, `app.composer.load` no longer accepts a component instance. Instead, pass in the body class and any attrs. For instance, + +```js +// Mithril 0.2 +app.composer.load(new DiscussionComposer({user: app.session.user})); + +// Mithril 2 +app.composer.load(DiscussionComposer, {user: app.session.user}) +``` + +Finally, functionality for confirming before unloading a page with an active composer has been moved into the `common/components/ConfirmDocumentUnload` component. + +#### Widget and DashboardWidget + +The redundant `admin/components/Widget` component has been removed. `admin/components/DashboardWidget` should be used instead. + +#### NotificationList + +For `forum/components/NotificationList`, the `clear`, `load`, `loadMore`, `parseResults`, and `markAllAsRead` methods have been moved to `forum/states/NotificationListState`. + +Methods for `isLoading` and `hasMoreResults` have been added to `forum/states/NotificationListState`. + +`app.cache.notifications` is no longer available; `app.notifications` (which points to an instance of `NotificationListState`) should be used instead. + +#### Checkbox + +Loading state in the `common/components/Checkbox` component is no longer managed through `this.loading`; it is now passed in as a prop (`this.attrs.loading`). + +#### Preference Saver + +The `preferenceSaver` method of `forum/components/SettingsPage` has been removed without replacement. This is done to avoid saving component instances. Instead, preferences should be directly saved. For instance: + +```js +// Old way +Switch.component({ + children: app.translator.trans('core.forum.settings.privacy_disclose_online_label'), + state: this.user.preferences().discloseOnline, + onchange: (value, component) => { + this.user.pushAttributes({ lastSeenAt: null }); + this.preferenceSaver('discloseOnline')(value, component); + }, +}) + +// Without preferenceSaver +Switch.component({ + children: app.translator.trans('core.forum.settings.privacy_disclose_online_label'), + state: this.user.preferences().discloseOnline, + onchange: (value) => { + this.discloseOnlineLoading = true; + + this.user.savePreferences({ discloseOnline: value }).then(() => { + this.discloseOnlineLoading = false; + m.redraw(); + }); + }, + loading: this.discloseOnlineLoading, +}) +``` + +A replacement will eventually be introduced. + +#### DiscussionListState + +For `forum/components/DiscussionList`, the `requestParams`, `sortMap`, `refresh`, `loadResults`, `loadMore`, `parseResults`, `removeDiscussion`, and `addDiscussion` methods have been moved to `forum/states/DiscussionListState`. + +Methods for `hasDiscussions`, `isLoading`, `isSearchResults`, and `empty` have been added to `forum/states/DiscussionListState`. + +`app.cache.discussions` is no longer available; `app.discussions` (which points to an instance of `DiscussionListState`) should be used instead. + +#### PageState + +`app.current` and `app.previous` no longer represent component instances, they are now instances of the `common/states/PageState` class. This means that: + +- Instead of `app.current instanceof X`, use `app.current.matches(X)` +- Instead of `app.current.PROPERTY`, use `app.current.get('PROPERTY')`. Please note that all properties must be exposed EXPLICITLY via `app.current.set('PROPERTY', VALUE)`. + +#### PostStream + +Logic from `forum/components/PostStreamScrubber`'s `update` method has been moved to `forum/components/PostStream`'s `updateScrubber` method. + +For `forum/components/PostStream`, the `update`, `goToFirst`, `goToLast`, `goToNumber`, `goToIndex`, `loadNearNumber`, `loadNearIndex`, `loadNext`, `loadPrevious`, `loadPage`, `loadRange`, `show`, `posts`, `reset`, `count`, and `sanitizeIndex` methods have been moved to `forum/states/PostStreamState`. + +Methods for `disabled` and `viewingEnd` have been added to `forum/states/PostStreamState`. + +#### SearchState and GlobalSearchState + +As with other components, we no longer store instances of `forum/components/Search`. As such, every `Search` component instance should be paired with a `forum/states/SearchState` instance. + +At the minimum, `SearchState` contains the following methods: + +- getValue +- setValue +- clear +- cache (adds a searched value to cache, meaning that we don't need to search for its results again) +- isCached (checks if a value has been searched for before) + +All of these methods have been moved from `Search` to `SearchState`. Additionally, Search's `stickyParams`, `params`, `changeSort`, `getInitialSearch`, and `clearInitialSearch` methods have been moved to `forum/states/GlobalSearchState`, which is now available via `app.search`. + +To use a custom search, you'll want to: + +1. Possibly create a custom subclass of `SearchState` +2. Create a custom subclass of `Search`, which overrides the `selectResult` method to handle selecting results as needed by your use case, and modify the `sourceItems` methods to contain the search sources you need. + +#### moment -> dayjs + +The `moment` library has been removed, and replaced by the `dayjs` library. The global `moment` can still be used for now, but is deprecated. `moment` and `dayjs` have very similar APIs, so very few changes will be needed. Please see the dayjs documentation [for more information](https://day.js.org/en/) on how to use it. + +#### Subtree Retainer + +`SubtreeRetainer` is a util class that makes it easier to avoid unnecessary redraws by keeping track of some pieces of data. When called, it checks if any of the data has changed; if not, it indicates that a redraw is not necessary. + +In mithril 0.2, its `retain` method returned a [subtree retain directive](https://mithril.js.org/archive/v0.1.25/mithril.render.html#subtree-directives) if no redraw was necessary. + +In mithril 2, we use its `needsRebuild` method in combination with `onbeforeupdate`. For instance: + +```js +class CustomComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + this.showContent = false; + + this.subtree = new SubtreeRetainer( + () => this.showContent, + ) + } + + onbeforeupdate() { + // If needsRebuild returns true, mithril will diff and redraw the vnode as usual. Otherwise, it will skip this redraw cycle. + // In this example, this means that this component and its children will only be redrawn when extra content is toggled. + return this.subtree.needsRebuild(); + } + + view(vnode) { + return
+ +

Hello World!{this.showContent ? ' Extra Content!' : ''}

+
; + } +} +``` + +#### attrs() method + +Previously, some components would have an attrs() method, which provided an extensible way to provide attrs to the top-level child vnode returned by `view()`. For instance, + +```js +class CustomComponent extends Component { + view() { + return

Hello World!

; + } + + attrs() { + return { + className: 'SomeClass', + onclick: () => console.log('click'), + }; + } +} +``` + +Since `this.attrs` is now used for attrs passed in from parent components, `attrs` methods have been renamed to `elementAttrs`. + +#### Children and .component + +Previously, an element could be created with child elements by passing those in as the `children` prop: + +```js +Button.component({ + className: 'Button Button--primary', + children: 'Button Text' +}); +``` + +This will no longer work, and will actually result in errors. Instead, the 2nd argument of the `component` method should be used: + +```js +Button.component({ + className: 'Button Button--primary' +}, 'Button Text'); +``` + +Children can still be passed in through JSX: + +```js + +``` + +#### Tag attr + +Because mithril uses 'tag' to indicate the actual html tag (or component class) used for a vnode, you can no longer pass `tag` as an attr to components extending Flarum's `Component` helper class. The best workaround here is to just use another name for this attr. + +#### affixSidebar + +The `affixSidebar` util has been removed. Instead, if you want to affix a sidebar, wrap the sidebar code in an `AffixedSidebar` component. For instance, + +```js +class OldWay extends Component { + view() { + return
+
+
+ +
Actual Page Content
+
+
+
; + } +} + +class NewWay extends Component { + view() { + return
+
+
+ + + +
Actual Page Content
+
+
+
; + } +} +``` + +#### Fragment + +**Warning: For Advanced Use Only** + +In some rare cases, we want to have extremely fine grained control over the rendering and display of some significant chunks of the DOM. These are attached with `m.render`, and do not experience automated redraws. Current use cases in core and bundled extensions are: + +- The "Reply" button that shows up when selecting text in a post +- The mentions autocomplete menu that shows up when typing +- The emoji autocomplete menu that shows up when typing + +For this purpose, we provide a helper class (`common/Fragment`), of which you can create an instance, call methods, and render via `m.render(DOM_ROOT, fragmentInstance.render())`. The main benefit of using the helper class is that it allows you to use lifecycle methods, and to access the underlying DOM via `this.$()`, like you would be able to do with a component. + +This should only be used when absolutely necessary. If you are unsure, you probably don't need it. If the goal is to not store component instances, the "state pattern" as described above is preferable. + +### Required Frontend Changes Recap + +Each of these changes has been explained above, this is just a recap of major changes for your convenience. + +- Component Methods: + - `view()` -> `view(vnode)` + - Lifecycle + - `init()` -> `oninit(vnode)` + - `config()` -> Lifecycle hooks `oncreate(vnode)` / `onupdate(vnode)` + - `context.onunload()` -> `onremove()` + - `SubtreeRetainer` -> `onbeforeupdate()` + - if present, `attrs()` method needs to be renamed -> convention `elementAttrs()` + - building component with `MyComponent.component()` -> `children` is now second parameter instead of a named prop/attr (first argument) -> JSX preferred +- Routing + - `m.route()` -> `m.route.get()` + - `m.route(name)` -> `m.route.set(name)` + - register routes with page class, not instance + - special case when passing props + - `` -> `` +- AJAX + - `m.request({...})` -> `data:` key split up into `body:` and `params:` + - `m.deferred` -> native `Promise` +- Redrawing + - `m.redraw(true)` -> `m.redraw.sync()` + - `m.redraw.strategy('none')` -> `e.redraw = false` in event handler + - `m.lazyRedraw()` -> `m.redraw()` + +#### Deprecated changes + +For the following changes, we currently provide a backwards-compatibility layer. This will be removed in time for the stable release. The idea is to let you release a new version that's compatible with Beta 14 to your users as quickly as possible. When you have taken care of the changes above, you should be good to go. For the following changes, we have bought you time until the stable release. Considering you have to make changes anyway, why not do them now? + +- `this.props` -> `this.attrs` +- static `initProps()` -> static `initAttrs()` +- `m.prop` -> `flarum/utils/Stream` +- `m.withAttr` -> `flarum/utils/withAttr` +- `moment` -> `dayjs` + +## Backend (PHP) + +### New Features + +#### Extension Dependencies + +Some extensions are based on, or add features to, other extensions. Prior to this release, there was no way to ensure that those dependencies were enabled before the extension that builds on them. Now, you cannot enable an extension unless all of its dependencies are enabled, and you cannot disable an extension if there are other enabled extensions depending on it. + +So, how do we specify dependencies for an extension? Well, all you need to do is add them as composer dependencies to your extension's `composer.json`! For instance, if we have an extension that depends on Tags and Mentions, our `composer.json` will look like this: + +```json +{ + "name": "my/extension", + "description": "Cool New Extension", + "type": "flarum-extension", + "license": "MIT", + "require": { + "flarum/core": "^0.1.0-beta.14", + "flarum/tags": "^0.1.0-beta.14", // Will mark tags as a dependency + "flarum/mentions": "^0.1.0-beta.14", // Will mark mentions as a dependency + } + // other config +} +``` + +#### View Extender + +Previously, when extensions needed to register Laravel Blade views, they could inject a view factory in `extend.php` and call it's `addNamespace` method. For instance, + +```php +// extend.php +use Illuminate\Contracts\View\Factory; + +return [ + function (Factory $view) { + $view->addNamespace(NAME, RELATIVE PATH); + } +] +``` + +This should NOT be used, as it will break views for all extensions that boot after yours. Instead, the `View` extender should be used: + +```php +// extend.php +use Flarum\Extend\View; + +return [ + (new View)->namespace(NAME, RELATIVE PATH); +] +``` + +#### Application and Container + +Although Flarum uses multiple components of the Laravel framework, it is not a pure Laravel system. In beta 14, the `Flarum\Foundation\Application` class no longer implements `Illuminate\Contracts\Foundation\Application`, and no longer inherits `Illuminate\Container\Container`. Several things to note: + +- The `app` helper now points to an instance of `Illuminate\Container\Container`, not `Flarum\Foundation\Application`. You might need to resolve things through the container before using them: for instance, `app()->url()` will no longer work; you'll need to resolve or inject an instance of `Flarum\Foundation\Config` and use that. +- Injected or resolved instances of `Flarum\Foundation\Application` can no longer resolve things through container methods. `Illuminate\Container\Container` should be used instead. +- Not all public members of `Illuminate\Contracts\Foundation\Application` are available through `Flarum\Foundation\Application`. Please refer to our [API docs on `Flarum\Foundation\Application`](https://api.docs.flarum.org/php/master/flarum/foundation/application) for more information. + +#### Other Changes + +- We are now using Laravel 6. Please see [Laravel's upgrade guide](https://laravel.com/docs/6.x/upgrade) for more information. Please note that we do not use all of Laravel. +- Optional params in url generator now work. For instance, the url generator can now properly generate links to posts in discussions. +- A User Extender has been added, which replaces the deprecated `PrepareUserGroups` and `GetDisplayName` events. +- Error handler middleware can now be manipulated by the middleware extender through the `add`, `remove`, `replace`, etc methods, just like any other middleware. +- `Flarum/Foundation/Config` and `Flarum/Foundation/Paths` can now be injected where needed; previously their data was accessible through `Flarum/Foundation/Application`. + +### Deprecations + +- `url` provided in `config.php` is now an array, accessible via `$config->url()`, for an instance of `Config` - [PR](https://github.com/flarum/core/pull/2271#discussion_r475930358) +- AssertPermissionTrait has been deprecated - [Issue](https://github.com/flarum/core/issues/1320) +- Global path helpers and path methods of `Application` have been deprecated, the injectable `Paths` class should be used instead - [PR](https://github.com/flarum/core/pull/2155) +- `Flarum\User\Event\GetDisplayName` has been deprecated, the `displayNameDriver` method of the `User` extender should be used instead - [PR](https://github.com/flarum/core/pull/2174) + +### Removals + +- Do NOT use the old closure notation for configuring view namespaces. This will break all extensions that boot after your extension. The `View` extender MUST be used instead. +- app()->url() will no longer work: [`Flarum\Http\UrlGenerator`](routes.md) should be injected and used instead. An instance of `Flarum\Http\UrlGenerator` is available in `blade.php` templates via `$url`. +- As a part of the Laravel 6 upgrade, the [`array_` and `str_` helpers](https://laravel.com/docs/6.x/upgrade#helpers) have been removed. +- The Laravel translator interface has been removed; the Symfony translator interface should be used instead: `Symfony\Component\Translation\TranslatorInterface` +- The Mandrill mail driver is no longer provided in Laravel 6, and has been removed. +- The following events deprecated in Beta 13 [have been removed](https://github.com/flarum/core/commit/7d1ef9d89161363d1c8dea19cf8aebb30136e9e3#diff-238957b67e42d4e977398cd048c51c73): + - `AbstractConfigureRoutes` + - `ConfigureApiRoutes` - Use the `Routes` extender instead + - `ConfigureForumRoutes` - Use the `Frontend` or `Routes` extenders instead + - `ConfigureLocales` - Use the `LanguagePack` extender instead + - `ConfigureModelDates` - Use the `Model` extender instead + - `ConfigureModelDefaultAttributes` - Use the `Model` extender instead + - `GetModelRelationship` - Use the `Model` extender instead + - `Console\Event\Configuring` - Use the `Console` extender instead + - `BioChanged` - User bio has not been a core feature for several releases diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md new file mode 100644 index 000000000..1e69a9282 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md @@ -0,0 +1,60 @@ +# Cập nhật cho Beta 15 + +Beta 15 features multiple new extenders, a total redesign of the admin dashboard, and several other interesting new features for extensions. As before, we have done our best to provide backwards compatibility layers, and we recommend switching away from deprecated systems as soon as possible to make your extensions more stable. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## New Features / Deprecations + +### Bộ mở rộng + +- `Flarum\Api\Event\WillGetData` and `Flarum\Api\Event\WillSerializeData` have been deprecated, the `ApiController` extender should be used instead +- `Flarum\Api\Event\Serializing` and `Flarum\Event\GetApiRelationship` have been deprecated, the `ApiSerializer` extender should be used instead +- `Flarum\Formatter\Event\Parsing` has been deprecated, the `parse` method of the `Formatter` extender should be used instead +- `Flarum\Formatter\Event\Rendering` has been deprecated, the `render` method of the `Formatter` extender should be used instead +- `Flarum\Notification\Event\Sending` has been deprecated, the `driver` method of the `Notification` extender should be used instead + - Please note that the new notification driver system is not an exact analogue of the old `Sending` event, as it can only add new drivers, not change the functionality of the default notification bell alert driver. If your extension needs to modify **how** or **to whom** notifications are sent, you may need to replace `Flarum\Notification\NotificationSyncer` on the service provider level +- `Flarum\Event\ConfigureNotificationTypes` has been deprecated, the `type` method of the `Notification` extender should be used instead +- `Flarum\Event\ConfigurePostTypes` has been deprecated, the `type` method of the `Post` extender should be used instead +- `Flarum\Post\Event\CheckingForFlooding` has been deprecated, as well as `Flarum\Post\Floodgate`. They have been replaced with a middleware-based throttling system that applies to ALL requests to /api/*, and can be configured via the `ThrottleApi` extender. Please see our [api-throttling](api-throttling.md) documentation for more information. +- `Flarum\Event\ConfigureUserPreferences` has been deprecated, the `registerPreference` method of the `User` extender should be used instead +- `Flarum\Foundation\Event\Validating` has been deprecated, the `configure` method of the `Validator` extender should be used instead + +- The Policy system has been reworked a bit to be more intuitive. Previously, policies contained both actual policies, which determine whether a user can perform some ability, and model visibility scopers, which allowed efficient restriction of queries to only items that users have access to. See the [authorization documentation](authorization.md) for more information on how to use the new systems. Now: + - `Flarum\Event\ScopeModelVisibility` has been deprecated. New scopers can be registered via the `ModelVisibility` extender, and any `Eloquent\Builder` query can be scoped by calling the `whereVisibleTo` method on it, with the ability in question as an optional 2nd argument (defaults to `view`). + - `Flarum\Event\GetPermission` has been deprecated. Policies can be registered via the `Policy` extender. `Flarum\User\User::can` has not changed. Please note that the new policies must return one of `$this->allow()`, `$this->deny()`, `$this->forceAllow()`, `$this->forceDeny()`, not a boolean. + +- A `ModelUrl` extender has been added, allowing new slug drivers to be registered. This accompanies Flarum's new slug driving system, which allows for extensions to define custom slugging strategies for sluggable models. The extender supports sluggable models outside of Flarum core. Please see our [model slugging](slugging.md) documentation for more information. +- A `Settings` extender has been added, whose `serializeToForum` method makes it easy to serialize a setting to the forum. +- A `ServiceProvider` extender has been added. This should be used with extreme caution for advanced use cases only, where there is no alternative. Please note that the service provider layer is not considered public API, and is liable to change at any time, without notice. + +### Admin UX Redesign + +The admin dashboard has been completely redesigned, with a focus on providing navbar pages for each extension. The API for extensions to register settings, permissions, and custom pages has also been greatly simplified. You can also now update your extension's `composer.json` to provide links for funding, support, website, etc that will show up on your extension's admin page. Please see [our Admin JS documentation](admin.md) for more information on how to use the new system. + +### Other New Features + +- On the backend, the route name is now available via `$request->getAttribute('routeName')` for controllers, and for middleware that run after `Flarum\Http\Middleware\ResolveRoute.php`. +- `Flarum\Api\Controller\UploadImageController.php` can now be used as a base class for controllers that upload images (like for the logo and favicon). +- Automatic browser scroll restoration can now be disabled for individual pages [see our frontend page documentation for more info](frontend-pages.md). + +## Breaking Changes + +- The following deprecated frontend BC layers were removed: + - `momentjs` no longer works as an alias for `dayjs` + - `this.props` and `this.initProps` no longer alias `this.attrs` and `this.initAttrs` for the `Component` base class + - `m.withAttr` and `m.stream` no longer alias `flarum/utils/withAttr` and `flarum/utils/Stream` + - `app.cache.discussionList` has been removed + - `this.content` and `this.editor` have been removed from `ComposerBody` + - `this.component`, `this.content`, and `this.value` have been removed from `ComposerState` +- The following deprecated backend BC layers were removed: + - The `publicPath`, `storagePath`, and `vendorPath` methods of `Flarum\Foundation\Application` have been removed + - The `base_path`, `public_path`, and `storage_path` global helpers have been removed + - The `getEmailSubject` method of `Flarum\Notification\MailableInterface` MUST now take a translator instance as an argument + - `Flarum\User\AssertPermissionTrait` has been removed, the analogous methods on `Flarum\User\User` should be used instead + - The `Flarum\Event\PrepareUserGroups` event has been removed, use the `User` extender instead + - The `Flarum\User\Event\GetDisplayName` event has been removed, use the display name driver feature of the `User` extender instead diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md new file mode 100644 index 000000000..257009432 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md @@ -0,0 +1,138 @@ +# Cập nhật cho Beta 16 + +Beta 16 finalizes the PHP extender API, introduces a testing library and JS typings, switches to using namespaces for JS imports, increases extension dependency robustness, and allows overriding routes, among other features. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Frontend + +- A new editor driver abstraction has been introduced, which allows extensions to override the default textarea-based editor with more advanced solutions. +- The `TextEditor` and `TextEditorButton` components, as well as the `BasicEditorDriver` util (which replaces `SuperTextarea`) have been moved from `forum` to `common`. +- The `forum`, `admin`, and `common` namespaces should be used when importing. So instead of `import Component from 'flarum/Component'`, use `import Component from 'flarum/common/Component`. Support for the old import styles will be deprecated through the stable release, and removed with Flarum 2.0. +- A typing library has been released to support editor autocomplete for frontend development, and can be installed in your dev environment via `npm install --save-dev flarum@0.1.0-beta.16`. +- Extension categories have been simplified down to `feature`, `theme`, and `language`. + +## Backend + +### Bộ mở rộng + +- All extenders that support callbacks/closures now support global functions like `'boolval'` and array-type functions like `[ClassName::class, 'methodName']`. +- The `Settings` extender's `serializeToFrontend` method now supports a default value as the 4th argument. +- The `Event` extender now supports registering subscribers for multiple events at once via a `subscribe` method. +- The `Notification` extender now has a `beforeSending` method, which allows you to adjust the list of recipients before a notification is sent. +- The `mutate` method of `ApiSerializer` has been deprecated, and renamed to `attributes`. +- `remove` methods on the `Route` and `Frontend` extenders can be used to remove (and then replace) routes. +- A `ModelPrivate` extender replaces the `GetModelIsPrivate` event, which has been deprecated. +- Methods on the `Auth` extender replace the `CheckingPassword` event, which has been deprecated. +- All search-related events are now deprecated in favor of the `SimpleFlarumSearch` and `Filter` extenders; this is explained in more detail below. + +### Laravel and Symfony + +Beta 16 upgrades from v6.x to v8.x of Laravel components and v4 to v5 of Symfony components. Please see the respective upgrade guides of each for changes you might need to make to your extensions. The most applicable change is the deprecation of `Symfony\Component\Translation\TranslatorInterface` in favor of `Symfony\Contracts\Translation\TranslatorInterface`. The former will be removed in beta 17. + +### Helper Functions + +The remaining `app` and `event` global helper functions have been deprecated. `app` has been replaced with `resolve`, which takes the name of a container binding and resolves it through the container. + +Since some Flarum extensions use Laravel libraries that assume some global helpers exist, we've recreated some commonly used helpers in the [flarum/laravel-helpers](https://github.com/flarum/laravel-helpers) package. These helpers should NOT be used directly in Flarum extension code; they are available so that Laravel-based libraries that expect them to exist don't malfunction. + +### Search Changes + +As part of our ongoing efforts to make Flarum's search system more flexible, we've made several refactors in beta 16. Most notably, filtering and searching are now treated as different mechanisms, and have separate pipelines and extenders. Essentially, if a query has a `filter[q]` query param, it will be treated as a search, and all other filter params will be ignored. Otherwise, it will be handled by the filtering system. This will eventually allow searches to be handled by alternative drivers (provided by extensions), such as ElasticSearch, without impacting filtering (e.g. loading recent discussions). Classes common to both systems have been moved to a `Query` namespace. + +Core's filtering and default search (named SimpleFlarumSearch) implementations are quite similar, as both are powered by the database. `List` API controllers call the `search` / `filter` methods on a resource-specific subclass of `Flarum\Search\AbstractSearcher` or `Flarum\Filter\AbstractFilterer`. Arguments are an instance of `Flarum\Query\QueryCriteria`, as well as sort, offset, and limit information. Both systems return an instance of `Flarum\Query\QueryResults`, which is effectively a wrapper around a collection of Eloquent models. + +The default systems are also somewhat similar in their implementation. `Filterer`s apply Filters (implementing `Flarum\Filter\FilterInterface`) based on query params in the form `filter[FILTER_KEY] = FILTER_VALUE` (or `filter[-FILTER_KEY] = FILTER_VALUE` for negated filters). SimpleFlarumSearch's `Searcher`s split the `filter[q]` param by spaces into "terms", apply Gambits (implementing `Flarum\Search\GambitInterface`) that match the terms, and then apply a "Fulltext Gambit" to search based on any "terms" that don't match an auxiliary gambit. Both systems then apply sorting, an offset, and a result count limit, and allow extensions to modify the query result via `searchMutators` or `filterMutators`. + +Extensions add gambits and search mutators and set fulltext gambits for `Searcher` classes via the `SimpleFlarumSearch` extender. They can add filters and filter mutators to `Filterer` classes via the `Filter` extender. + +With regards to upgrading, please note the following: + +- Search mutations registered by listening to the `Searching` events for discussions and users will be applied as to searches during the search mutation step via a temporary BC layer. They WILL NOT be applied to filters. This is a breaking change. These events have been deprecated. +- Search gambits registered by listening to the `ConfigureUserGambits` and `ConfigureDiscussionGambits` events will be applied to searcher via a temporary BC layer. They WILL NOT be applied to filters. This is a breaking change. These events have been deprecated. +- Post filters registered by listening to the `ConfigurePostsQuery` events will be applied to post filters via a temporary BC layer. That event has been deprecated. + +### Testing Library + +The `flarum/testing` package provides utils for PHPUnit-powered automated backend tests. See the [testing documentation](testing.md) for more info. + +### Optional Dependencies + +Beta 15 introduced "extension dependencies", which require any extensions listed in your extension's `composer.json`'s `require` section to be enabled before your extension can be enabled. + +With beta 16, you can specify "optional dependencies" by listing their composer package names as an array in your extension's `extra.flarum-extension.optional-dependencies`. Any enabled optional dependencies will be booted before your extension, but aren't required for your extension to be enabled. + +### Access Token and Authentication Changes + +#### Extension API changes + +The signature to various method related to authentication have been changed to take `$token` as parameter instead of `$userId`. Other changes are the result of the move from `$lifetime` to `$type` + +- `Flarum\Http\AccessToken::generate($userId)` no longer accepts `$lifetime` as a second parameter. Parameter has been kept for backward compatibility but has no effect. It will be removed in beta 17. +- `Flarum\Http\RememberAccessToken::generate($userId)` should be used to create remember access tokens. +- `Flarum\Http\DeveloperAccessToken::generate($userId)` should be used to create developer access tokens (don't expire). +- `Flarum\Http\SessionAccessToken::generate()` can be used as an alias to `Flarum\Http\AccessToken::generate()`. We might deprecate `AccessToken::generate()` in the future. +- `Flarum\Http\Rememberer::remember(ResponseInterface $response, AccessToken $token)`: passing an `AccessToken` has been deprecated. Pass an instance of `RememberAccessToken` instead. As a temporary compatibility layer, passing any other type of token will convert it into a remember token. In beta 17 the method signature will change to accept only `RememberAccessToken`. +- `Flarum\Http\Rememberer::rememberUser()` has been deprecated. Instead you should create/retrieve a token manually with `RememberAccessToken::generate()` and pass it to `Rememberer::remember()` +- `Flarum\Http\SessionAuthenticator::logIn(Session $session, $userId)` second parameter has been deprecated and is replaced with `$token`. Backward compatibility is kept. In beta 17, the second parameter method signature will change to `AccessToken $token`. +- `AccessToken::generate()` now saves the model to the database before returning it. +- `AccessToken::find($id)` or `::findOrFail($id)` can no longer be used to find a token, because the primary key was changed from `token` to `id`. Instead you can use `AccessToken::findValid($tokenString)` +- It's recommended to use `AccessToken::findValid($tokenString): AccessToken` or `AccessToken::whereValid(): Illuminate\Database\Eloquent\Builder` to find a token. This will automatically scope the request to only return valid tokens. On forums with low activity this increases the security since the automatic deletion of outdated tokens only happens every 50 requests on average. + +#### Symfony session changes + +If you are directly accessing or manipulating the Symfony session object, the following changes have been made: + +- `user_id` attribute is no longer used. `access_token` has been added as a replacement. It's a string that maps to the `token` column of the `access_tokens` database table. + +To retrieve the current user from inside a Flarum extension, the ideal solution which was already present in Flarum is to use `$request->getAttribute('actor')` which returns a `User` instance (which might be `Guest`) + +To retrieve the token instance from Flarum, you can use `Flarum\Http\AccessToken::findValid($tokenString)` + +To retrieve the user data from a non-Flarum application, you'll need to make an additional database request to retrieve the token. The user ID is present as `user_id` on the `access_tokens` table. + +#### Token creation changes + +The `lifetime` property of access tokens has been removed. Tokens are now either `session` tokens with 1h lifetime after last activity, or `session_remember` tokens with 5 years lifetime after last activity. + +The `remember` parameter that was previously available on the `POST /login` endpoint has been made available on `POST /api/token`. It doesn't return the remember cookie itself, but the token returned can be used as a remember cookie. + +The `lifetime` parameter of `POST /api/token` has been deprecated and will be removed in Flarum beta 17. Partial backward compatibility has been provided where a `lifetime` value longer than 3600 seconds is interpreted like `remember=1`. Values lower than 3600 seconds result in a normal non-remember token. + +New `developer` tokens that don't expire have been introduced, however they cannot be currently created through the REST API. Developers can create developer tokens from an extension using `Flarum\Http\DeveloperAccessToken::generate($userId)`. + +If you manually created tokens in the database from outside Flarum, the `type` column is now required and must contain `session`, `session_remember` or `developer`. Tokens of unrecognized type cannot be used to authenticate, but won't be deleted by the garbage collector either. In a future version extensions will be able to register custom access token types. + +#### Token usage changes + +A [security issue in Flarum](https://github.com/flarum/core/issues/2075) previously caused all tokens to never expire. This had limited security impact due to tokens being long unique characters. However custom integrations that saved a token in an external database for later use might find the tokens no longer working if they were not used recently. + +If you use short-lived access tokens for any purpose, take note of the expiration time of 1h. The expiration is based on the time of last usage, so it will remain valid as long as it continues to be used. + +Due to the large amount of expired tokens accumulated in the database and the fact most tokens weren't ever used more than once during the login process, we have made the choice to delete all access tokens a lifetime of 3600 seconds as part of the migration, All remaining tokens have been converted to `session_remember` tokens. + +#### Remember cookie + +The remember cookie still works like before, but a few changes have been made that could break unusual implementations. + +Now only access tokens created with `remember` option can be used as remember cookie. Any other type of token will be ignored. This means if you create a token with `POST /api/token` and then place it in the cookie manually, make sure you set `remember=1` when creating the token. + +#### Web session expiration + +In previous versions of Flarum, a session could be kept alive forever until the Symfony session files were deleted from disk. + +Now sessions are linked to access tokens. A token being deleted or expiring will automatically end the linked web session. + +A token linked to a web session will now be automatically deleted from the database when the user clicks logout. This prevents any stolen token from being re-used, but it could break custom integration that previously used a single access token in both a web session and something else. + +### Miscellaneous + +- The IP address is now available in requests via `$request->getAttribute('ipAddress')` +- Policies can now return `true` and `false` as aliases for `$this->allow()` and `$this->deny()`, respectively. +- The `user.edit` permission has been split into `user.editGroups`, `user.editCredentials` (for email, username, and password), and `user.edit` (for other attributes). +- There are now permissions (`bypassTagCounts`) that allow users to bypass tag count requirements. +- Flarum now supports PHP 7.3 - PHP 8.0, with support for PHP 7.2 officially dropped. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md new file mode 100644 index 000000000..5a1b82884 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md @@ -0,0 +1,114 @@ +# Cập nhật cho Beta 8 + +All extensions will need to be refactored in order to work with beta 8. Here are the main things you will need to do in order to make your extension compatible. + +:::caution + +This guide is not comprehensive. You may encounter some changes we haven't documented. If you need help, start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## PHP Namespaces + +Beta 8 comes with large changes to the overall structure of the PHP backend. You will need to look through [this list](https://discuss.flarum.org/d/6572-help-us-namespace-changes) of namespace changes and make changes to your extension accordingly. + +[This script](https://gist.github.com/tobyzerner/55e7c05c95404e5efab3a9e43799d375) can help you to automate most of the namespace changes. Of course, you should still test your extension after running the script as it may miss something. + +## Database Naming + +Many database columns and JSON:API attributes have been renamed to conform to a [convention](/contributing.md#database). You will need to update any instances where your extension interacts with core data. You can see the changes in [#1344](https://github.com/flarum/core/pull/1344/files). + +## Bộ mở rộng + +Beta 8 introduces a new concept called **extenders** that replace the most common event listeners. You can learn more about how they work in the [updated extension docs](start.md#extenders). + +`bootstrap.php` has been renamed to `extend.php` and returns an array of extender instances and functions: + +```php +use Flarum\Extend; + +return [ + (new Extend\Frontend('forum')) + ->js(__DIR__.'/js/dist/forum.js') + ->css(__DIR__.'/less/forum.less') + ->route('/t/{slug}', 'tag') + ->route('/tags', 'tags'), + + function (Dispatcher $events) { + $events->subscribe(Listener\AddForumTagsRelationship::class); + } +] +``` + +If you're listening for any of the following events, you'll need to update your code to use an extender instead. See the relevant docs for more information. + +| Event | Extender | +| ------------------------------------- | --------------------------- | +| `Flarum\Event\ConfigureFormatter`* | `Flarum\Extend\Formatter` | +| `Flarum\Event\ConfigureWebApp`* | `Flarum\Extend\Frontend` | +| `Flarum\Event\ConfigureClientView`* | `Flarum\Extend\Frontend` | +| `Flarum\Event\ConfigureLocales` | `Flarum\Extend\Locales` | +| `Flarum\Event\ConfigureApiRoutes` | `Flarum\Extend\Routes` | +| `Flarum\Event\ConfigureForumRoutes` | `Flarum\Extend\Routes` | + +_\* class no longer exists_ + +## JavaScript Tooling + +Previously Flarum and its extensions used a custom Gulp workflow to compile ES6 source code into something that browsers could understand. Beta 8 switches to a more conventional approach with Webpack. + +You will need to tweak the structure of your extension's `js` directory. Currently, your JS file hierarchy looks something like the following: + +``` +js +├── admin +│ ├── src +│ │ └── main.js +│ ├── dist +│ │ └── extension.js +│ ├── Gulpfile.js +│ └── package.json +└── forum + ├── src + │ └── main.js + ├── dist + │ └── extension.js + ├── Gulpfile.js + └── package.json +``` + +You'll need to make the following changes: + +1. Update `package.json` and create `webpack.config.js`, `forum.js`, and `admin.js` files using [these templates](frontend.md#transpilation). + +2. Inside your `admin` and `forum` *folders*, delete `Gulpfile.js`, `package.json`, and `dist`. Then inside each `src` folder, rename `main.js` to `index.js`. Now move all of the `src` files outside of `src` folder and delete it. + +3. In the root `js` folder create a folder called `src` and move your `admin` and `forum` *folders* into it. + +4. While still in your root `js` folder, run `npm install` and then `npm run build` to build the new JS dist files. + +If everything went right, your folder structure should look something like this: + +``` +js +├── src +│ ├── admin +│ │ └── index.js +│ └── forum +│ └── index.js +├── dist +│ ├── admin.js +│ ├── admin.js.map +│ ├── forum.js +│ └── forum.js.map +├── admin.js +├── forum.js +├── package.json +└── webpack.config.js +``` + +Take a look at the [bundled extensions](https://github.com/flarum) for more examples. + +## Font Awesome Icons + +Beta 8 upgrades to Font Awesome 5, in which icon class names have changed. The `flarum/helpers/icon` helper now requires the **full Font Awesome icon class names** to be passed, eg. `fas fa-bolt`. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/views.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/views.md new file mode 100644 index 000000000..fc4a75a86 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extend/views.md @@ -0,0 +1,63 @@ +# Views and Blade + +Although the Flarum UI you know and love is powered by our [Mithril frontend](frontend), server-side generated templates are still used throughout Flarum. Most notably, the HTML skeleton of the forum, which includes various SEO meta tags, as well as the no-js view of the forum, is implemented through the Views and Blade systems. + +[Blade](https://laravel.com/docs/8.x/blade) is Laravel's templating engine, which allows you to conveniently generate HTML (or other static content) from PHP. It's the same idea as [Jinja](https://jinja.palletsprojects.com/en/3.0.x/) or [EJS](https://ejs.co/). [Views](https://laravel.com/docs/8.x/views) are Laravel's system for organizing/registering Blade templates, and also includes utilities for rendering them and providing them with variables. + +For our purposes, views are directories containing `.blade.php` template files (possibly contained in subdirectories). + +## Adding Views + +You will need to tell the view factory where it can find your extension's view files by adding a `View` extender to `extend.php`: + +```php +use Flarum\Extend; +use Illuminate\Contracts\View\Factory; + +return [ + (new Extend\View) + ->namespace('acme.hello-world', __DIR__.'/views'), +]; +``` + + +## Blade Templates + +To learn about the syntax for Blade templates, read [Laravel's documentation](https://laravel.com/docs/8.x/blade). + +Once you've set up your views, you can render them to strings: + +```php +// Here, $view is of type `Illuminate\Contracts\View\Factory` +$renderedString = $view->make('acme.hello-world::greeting')->render(); + +// You can also pass variables to the view: +$renderedString = $view->make('acme.hello-world::greeting', ['varName' => true])->render(); +``` + +You can obtain the view factory instance through dependency injection. + +The format is `"VIEW_NAMESPACE::VIEW_NAME"`. If the view folder is organized as subdirectories, replace `/` with `.` in the pack. So if you have a file at `"forum/error.blade.php"` in a namespace called `"custom-views"`, you would use `"custom-views::forum.error"`. + +Note that all Blade templates rendered this way automatically have access to the following variables: + +- `$url`: a [URL generator](routes#generating-urls) instance. +- `$translator`: a [Translator](i18n#server-side-translation) instance. +- `$settings`: a [SettingsInterface](settings) instance. +- `$slugManager`: a [SlugManager](slugging) instance. + +Additionally, templates used by [content logic](routes#content) have access to `$forum`, which represents the [Forum API Document's attributes](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Serializer/ForumSerializer.php#L19). + +## Overriding Views + +If you want to override templates added by core or extensions, set up a view folder structure matching the one you are trying to override, containing just the files you are trying to override. Then use the `View` extender's `extendNamespace` method: + +```php +use Flarum\Extend; +use Illuminate\Contracts\View\Factory; + +return [ + (new Extend\View) + ->extendNamespace('acme.hello-world', __DIR__.'/override_views'); +]; +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extenders.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extenders.md new file mode 100644 index 000000000..782df2f1b --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extenders.md @@ -0,0 +1,23 @@ +# Bộ mở rộng cục bộ + +Nếu có các tùy chỉnh bạn muốn thực hiện cho trang web của mình mà không phân phối toàn bộ tiện ích mở rộng, bạn có thể làm như vậy bằng cách sử dụng **bộ mở rộng cục bộ**. Mỗi bản cài đặt Flarum đều đi kèm với một tệp `extend.php` nơi bạn có thể thêm các đối tượng bộ mở rộng, giống như trong một phần mở rộng đầy đủ. + +Xem [tài liệu mở rộng của chúng tôi](extend/start.md) để biết thêm thông tin về bộ mở rộng (và cả [ví dụ về bộ mở rộng cục bộ](extend/start.md#hello-world)). + +Nếu bạn cần tạo tệp mới (khi thêm class tùy chỉnh được nhập cho bộ mở rộng), bạn sẽ cần điều chỉnh composer.json của mình một chút. Thêm những dòng sau: + +```json +"autoload": { + "psr-4": { + "App\\": "app/" + } +}, +``` + +Giờ đây, bạn có thể tạo các tệp PHP mới trong thư mục con `ứng dụng` bằng cách sử dụng namespace `App\...`. + +:::tip Bộ mở rộng cục bộ với Tiện ích mở rộng + +Các bộ mở rộng cục bộ có thể tốt cho các chỉnh sửa nhỏ, nhưng nếu bạn cần các tùy chỉnh lớn, một tiện ích mở rộng có thể là lựa chọn tốt hơn: một cơ sở mã riêng biệt, xử lý tốt hơn nhiều tệp, công cụ dành cho nhà phát triển và khả năng dễ dàng mã nguồn mở là những lợi ích lớn. + +::: diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extensions.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extensions.md new file mode 100644 index 000000000..ad0e91369 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/extensions.md @@ -0,0 +1,118 @@ +# Tiện ích mở rộng + +Flarum là tối giản, nhưng nó cũng có khả năng mở rộng cao. Trên thực tế, hầu hết các tính năng đi kèm với Flarum thực sự là phần mở rộng! + +Cách tiếp cận này làm cho Flarum cực kỳ tùy biến: Bạn có thể tắt bất kỳ tính năng nào bạn không cần và cài đặt các tiện ích mở rộng khác để làm cho diễn đàn của bạn trở nên hoàn hảo cho cộng đồng của bạn. + +Để biết thêm thông tin về triết lý của Flarum về những tính năng mà chúng tôi đưa vào cốt lõi hoặc nếu bạn đang muốn tạo tiện ích mở rộng của riêng mình, vui lòng xem [tài liệu về tiện ích mở rộng](extend/README.md) của chúng tôi. Bài viết này sẽ tập trung vào việc quản lý các tiện ích mở rộng từ góc độ của quản trị viên diễn đàn. + +## Extension Manager + +The extension manager is an extension that comes bundled with Flarum when installed via an archive. It provides a graphical interface for installing and updating both extensions and Flarum itself. + +If you do not have the extension manager installed and you wish to install it, you can do so by running the following command in your Flarum directory: + +```bash +composer require flarum/extension-manager:"*" +``` + +:::warning + +The extension manager allows an admin user to install any composer package. Only install the extension manager if you trust all of your forum admins with such permissions. + +::: + +![extension manager admin page](https://github.com/flarum/docs/assets/20267363/d0e1f7a5-e194-4acd-af63-7b8ddd95c26b) + + +## Tìm Tiện ích mở rộng + +Flarum có một hệ sinh thái đa dạng các tiện ích mở rộng, hầu hết đều là mã nguồn mở và miễn phí. Để tìm các tiện ích mở rộng mới và tuyệt vời, hãy truy cập thẻ [Tiện ích mở rộng](https://discuss.flarum.org/t/extensions) trên các diễn đàn cộng đồng của Flarum. [Cơ sở dữ liệu mở rộng Extiverse](https://extiverse.com/) không chính thức cũng là một tài nguyên tuyệt vời. + +## Cài đặt Tiện ích mở rộng + +### Through the interface + +Using the extension manager extension, you can install extensions directly from the admin dashboard. Once you have browsed the list of available extensions from the links above, and found one you want to install, you can install it by entering the extension's composer package name into the extension manager's installation input. + +![Installing an extension](/en/img/install-extension.png) + +### Through the command line + +Cũng giống như Flarum, các tiện ích mở rộng được cài đặt thông qua [Composer](https://getcomposer.org), sử dụng SSH. Để cài đặt một tiện ích mở rộng điển hình: + +1. `cd` vào thư mục Flarum của bạn. Thư mục này phải chứa các tệp `composer.json`, `flarum` và thư mục ` storage ` (trong số các tệp khác). Bạn có thể kiểm tra nội dung thư mục qua `ls -la`. +2. Chạy ` composer require TÊN_GÓI_COMPOSER:*`. Điều này sẽ được cung cấp bởi tài liệu của phần mở rộng. + +## Cập nhật Tiện ích mở rộng + +### Through the interface + +Using the extension manager extension, you can update extensions directly from the admin dashboard. You can run a check for updates by clicking the "Check for updates" button in the extension manager. If there are updates available, you can update all extensions by clicking the "Global update" button. Or, you can update individual extensions by clicking the "Update" button next to the extension you want to update. + +![Updating an extension](/en/img/update-extension.png) + +### Through the command line + +Thực hiện theo các hướng dẫn do nhà phát triển tiện ích mở rộng cung cấp. Nếu bạn đang sử dụng `*` làm chuỗi phiên bản cho các tiện ích mở rộng ([như được khuyến nghị](composer.md)), hãy chạy các lệnh được liệt kê trong [Hướng dẫn nâng cấp Flarum](update.md) sẽ cập nhật tất cả các tiện ích mở rộng của bạn. + +## Gỡ cài đặt Tiện ích mở rộng + +### Through the interface + +Using the extension manager extension, you can uninstall extensions directly from the admin dashboard. You can uninstall an extension by clicking the "Uninstall" button next to the extension you want to uninstall inside the extension's page. + +![Uninstalling an extension](/en/img/uninstall-extension.png) + +### Through the command line + +Tương tự như cài đặt, để xóa tiện ích mở rộng: + +0. Nếu bạn muốn xóa tất cả các bảng cơ sở dữ liệu được tạo bởi tiện ích mở rộng, hãy nhấp vào nút "Gỡ cài đặt" trong trang tổng quan quản trị. Xem [bên dưới](#managing-extensions) để biết thêm thông tin. +1. `cd` vào thư mục Flarum của bạn. +2. Chạy `composer remove TÊN_GÓI_COMPOSER`. Điều này sẽ được cung cấp bởi tài liệu của phần mở rộng. + +## Quản lý Tiện ích mở rộng + +Each individual extension page of the admin dashboard provides a convenient way to manage the extension. Bạn có thể: + +- Enable or disable the extension. +- See the settings provided by the extension, and change them. +- Hoàn tác quá trình di chuyển của tiện ích mở rộng để xóa bất kỳ sửa đổi cơ sở dữ liệu nào mà nó đã thực hiện (điều này có thể được thực hiện bằng nút Gỡ cài đặt). Thao tác này sẽ xóa TẤT CẢ dữ liệu được liên kết với tiện ích mở rộng và không thể hoàn tác được. Việc này chỉ nên được thực hiện khi bạn đang xóa một tiện ích mở rộng và không có kế hoạch cài đặt lại. Nó cũng hoàn toàn là tùy chọn. +- See the extension's README, if it has one. +- See the extension's version. +- Uninstall the extension if the extension manager is installed. + +## Configuring additional extension repository sources + +The extension manager uses `composer` under the hood, and as such, it looks for extension packages in the same places as `composer`. By default, this is [Packagist](https://packagist.org/). However, you can configure additional sources for the extension manager to look for extensions in. This is useful if you want to install an extension that is not available on Packagist. + +In the admin page of the extension manager, clicking the **Add Repository** button will open a modal where you can enter the name and URL of the repository you want to add. The name is just a label for the repository, and can be anything you want. The URL should be the URL of the repository which depends on the type of repository you want to add. + +### Adding a repository from a VCS + +If you want to add a repository from a VCS (e.g. GitHub, GitLab, BitBucket, etc), the URL should be the URL of the repository's VCS. For example, if you had a private GitHub repository at `https://github.com/acme/flarum-extension`, you would enter that URL into the URL field. If it is a private source, you will need to enter an authentication method through the **New authentication method** button. The token can be generated from your VCS provider's website, and the host should be the domain of the VCS provider (e.g. `github.com`). + +### Adding a composer repository + +Extiverse provides access to premium extensions. It is a good example of a composer repository. You would specify the URL as `https://flarum.org/composer/` and the name as `premium`. You would also need to enter an authentication method through the **New authentication method** button. The token can be generated from your Flarum account's [subscriptions](https://flarum.org/dashboard/subscriptions) page with the Instructions button. + +* Type: `HTTP Bearer` +* Host: `flarum.org` + +![Configure repositories](/en/img/config-repositories.png) + +:::info + +The configured repositories and auth methods will be active for both the command line and the admin dashboard. If you configure them from the command line however, you must not include the flag `--global`. + +::: + +## Installing Non-stable extensions + +If for whatever reason you want to install a non-stable extension (e.g. a beta, alpha or RC version) you must first update the **Minimum stability** setting to the wanted stability. + +* If you set it to Alpha, you will be able to install alpha, beta, RC (Release Candidate) and stable versions. +* If you set it to Beta, you will be able to install beta, RC and stable versions. +* If you set it to RC, you will be able to install RC and stable versions. +* If you set it to Stable, you will only be able to install stable versions. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/faq.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/faq.md new file mode 100644 index 000000000..2aa209ae9 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/faq.md @@ -0,0 +1,35 @@ +# FAQ + +### Flarum có ổn định không? + +Có! Sau 6 năm phát triển, Flarum 1.0.0 cuối cùng cũng có mặt ở đây. + +### Điều gì tiếp theo sau phiên bản ổn định? + +Chúng tôi vẫn đang làm việc trên một lộ trình chính thức. Chúng tôi có rất nhiều kế hoạch và ý tưởng, và mong muốn được chia sẻ một cột mốc kỹ lưỡng hơn với cộng đồng. + +### Tôi có thể ủng hộ tiền để đẩy nhanh quá trình phát triển? + +Mọi đóng góp đều được nhận với lòng biết ơn. Bạn có thể đóng góp trên [Nhà tài trợ GitHub](https://github.com/sponsors/flarum) hoặc [OpenCollective](https://opencollective.com/flarum). + +Tuy nhiên, các khoản đóng góp sẽ không tác động trực tiếp đến tốc độ phát triển của Flarum. Chúng tôi cũng khuyến khích người dùng đóng góp theo những cách khác, chẳng hạn như [đóng góp mã](contributing.md), [tiện ích mở rộng xây dựng](/extend/README.md), viết tài liệu, dịch Flarum sang các ngôn ngữ khác, cung cấp trợ giúp và hỗ trợ trên [cộng đồng diễn đàn](https://discuss.flarum.org/)... và chỉ là một nguồn năng lượng tích cực chung cho cộng đồng! + +### Liệu Flarum có [chèn tính năng vào đây] không? Khi nào? Tại sao không? + +Chúng tôi muốn xây dựng vô số tính năng và tiện ích mở rộng cho Flarum, nhưng điều đầu tiên trước tiên: Chúng tôi tập trung vào các yếu tố cần thiết và sự ổn định. + +### Tại sao vẫn chưa khắc phục được [thêm sự cố vào đây]? + +Ở đây một lần nữa, câu trả lời là "những điều đầu tiên trước tiên". Nếu chúng tôi chưa khắc phục được một vấn đề (hoặc chỉ định cho nó một cột mốc quan trọng), thì đó là vì chúng tôi đang làm việc khác cũng quan trọng không kém. những điều đầu tiên trước tiên ”. Xin hãy kiên nhẫn; chúng tôi sẽ cố gắng hoàn thành nó trước khi phát hành. Hoặc nếu bạn đang vội, vui lòng tự sửa và [đóng góp cho dự án](contributing.md)! + +### Có thể di chuyển diễn đàn của tôi qua Flarum được không? + +Chúng tôi hiện không cung cấp người di cư chính thức, nhưng có rất nhiều giải pháp cộng đồng hiện có. Tương đối sớm, chúng tôi sẽ bắt đầu xây dựng các công cụ để nhập dữ liệu từ các phần mềm diễn đàn khác như esoTalk, FluxBB, phpBB, Discourse và các phần mềm khác. + +### Làm thế nào để gia nhập đội ngũ Flarum? + +> "Thông qua một thử thách phức tạp và gian khổ, liên quan đến các nghi lễ thần bí, nguy hiểm đe dọa tính mạng và cuộc phiêu lưu đến những vùng đất xa xôi nơi nhiều người đi và một số ít trở về." ~ jordanjay29 + +Câu trả lời thực sự là chúng tôi thường để mắt đến cộng đồng của mình để tìm kiếm những thành viên nổi bật, những người sẽ tạo ra những nhân viên giỏi. Thành thật mà nói, đối với hầu hết các nhân viên hiện tại của chúng tôi, những gì họ đã làm trước khi trở thành nhân viên không khác nhiều so với những gì họ làm bây giờ. + +Tìm đam mê và đóng góp theo cách bạn cảm thấy tốt nhất. Sau đó, hãy để nó diễn ra theo hướng của nó. Bạn không cần phải có huy hiệu để được tôn trọng ở đây. \ No newline at end of file diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/install.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/install.md new file mode 100644 index 000000000..da8c2b5d8 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/install.md @@ -0,0 +1,198 @@ +# Cài đặt + +:::tip Kiểm tra nhanh driver? + +Vui lòng tham gia Flarum trên một trong những [diễn đàn demo](https://discuss.flarum.org/d/21101) của chúng tôi. Hoặc thiết lập diễn đàn của riêng bạn trong vài giây tại [Flarum miễn phí](https://www.freeflarum.com), một dịch vụ cộng đồng miễn phí không liên kết với nhóm Flarum. + +::: + +## Yêu cầu máy chủ + +Trước khi bạn cài đặt Flarum, điều quan trọng là phải kiểm tra xem máy chủ của bạn có đáp ứng các yêu cầu hay không. Để chạy Flarum, bạn sẽ cần: + +* **Apache** (đã bật mod_rewrite) hoặc **Nginx** +* **PHP 7.3+** với các tiện ích mở rộng sau: curl, dom, fileinfo, gd, json, mbstring, openssl, pdo\_mysql, tokenizer, zip +* **MySQL 5.6+/8.0.23+** hoặc **MariaDB 10.0.5+** +* **SSH (command-line) access** to run potentially necessary software maintenance commands, and Composer if you intend on using the command-line to install and manage Flarum extensions. + +## Cài đặt + +### Installing by unpacking an archive + +If you don't have SSH access to your server or you prefer not to use the command line, you can install Flarum by unpacking an archive. Below is a list of the available archives, make sure you choose the one that matches your PHP version and public path or lack thereof preference. + +| Flarum Version | PHP Version | Public Path | Type | Archive | +| -------------- | ----------------- | ----------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1.x | 8.3 (recommended) | No | ZIP | [flarum-v1.x-no-public-dir-php8.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.3.zip) | +| 1.x | 8.3 (recommended) | Yes | TAR.GZ | [flarum-v1.x-php8.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.3.tar.gz) | +| 1.x | 8.3 (recommended) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.3.tar.gz) | +| 1.x | 8.3 (recommended) | Yes | ZIP | [flarum-v1.x-php8.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.3.zip) | +| 1.x | 8.2 (recommended) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.2.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.2.tar.gz) | +| 1.x | 8.2 (recommended) | Yes | TAR.GZ | [flarum-v1.x-php8.2.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.2.tar.gz) | +| 1.x | 8.2 (recommended) | No | ZIP | [flarum-v1.x-no-public-dir-php8.2.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.2.zip) | +| 1.x | 8.2 (recommended) | Yes | ZIP | [flarum-v1.x-php8.2.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.2.zip) | +| 1.x | 8.1 | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.1.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.1.tar.gz) | +| 1.x | 8.1 | Yes | TAR.GZ | [flarum-v1.x-php8.1.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.1.tar.gz) | +| 1.x | 8.1 | No | ZIP | [flarum-v1.x-no-public-dir-php8.1.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.1.zip) | +| 1.x | 8.1 | Yes | ZIP | [flarum-v1.x-php8.1.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.1.zip) | +| 1.x | 8.0 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.0.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.0.tar.gz) | +| 1.x | 8.0 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php8.0.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.0.tar.gz) | +| 1.x | 8.0 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php8.0.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.0.zip) | +| 1.x | 8.0 (end of life) | Yes | ZIP | [flarum-v1.x-php8.0.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.0.zip) | +| 1.x | 7.4 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php7.4.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.4.tar.gz) | +| 1.x | 7.4 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php7.4.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.4.tar.gz) | +| 1.x | 7.4 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php7.4.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.4.zip) | +| 1.x | 7.4 (end of life) | Yes | ZIP | [flarum-v1.x-php7.4.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.4.zip) | +| 1.x | 7.3 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php7.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.3.tar.gz) | +| 1.x | 7.3 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php7.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.3.tar.gz) | +| 1.x | 7.3 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php7.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.3.zip) | +| 1.x | 7.3 (end of life) | Yes | ZIP | [flarum-v1.x-php7.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.3.zip) | + +### Installing using the Command Line Interface + +Flarum sử dụng [Composer](https://getcomposer.org) để quản lý các phần phụ thuộc và tiện ích mở rộng của nó. Nếu bạn không quen thuộc với nó, hãy đọc [hướng dẫn của chúng tôi](composer.md) để biết thông tin về nó là gì và cách thiết lập nó. Sau đó, chạy lệnh này ở một vị trí trống mà bạn muốn cài đặt Flarum: + +```bash +composer create-project flarum/flarum . +``` + +Trong khi lệnh này đang chạy, bạn có thể định cấu hình máy chủ web của mình. Bạn sẽ cần đảm bảo rằng webroot của mình được đặt thành `/path/to/your/forum/public` và thiết lập [Rewriting URL](#url-rewriting) như theo hướng dẫn bên dưới. + +Khi mọi thứ đã sẵn sàng, hãy điều hướng đến diễn đàn của bạn trong trình duyệt web và làm theo hướng dẫn để hoàn tất cài đặt. + +If you wish to install and update extensions from the admin dashboard, you need to also install the [Extension Manager](extensions.md) extension. + +```bash +composer require flarum/extension-manager:* +``` + +:::warning + +The extension manager allows an admin user to install any composer package. Only install the extension manager if you trust all of your forum admins with such permissions. + +::: + +## URL Rewriting + +### Apache + +Flarum bao gồm một tệp `.htaccess` trong thư mục `public` - đảm bảo rằng nó đã được tải lên chính xác. **Flarum sẽ không hoạt động bình thường nếu `mod_rewrite` không được bật hoặc `.htaccess` không được phép. ** Hãy nhớ kiểm tra với nhà cung cấp dịch vụ lưu trữ của bạn (hoặc VPS của bạn) mà các tính năng này được bật. Nếu bạn đang quản lý máy chủ của riêng mình, bạn có thể cần thêm phần sau vào cấu hình trang web của mình để kích hoạt các tệp `.htaccess`: + +``` + + AllowOverride All + +``` + +Điều này đảm bảo rằng các ghi đè htaccess được cho phép để Flarum có thể viết lại URL đúng cách. + +Các phương pháp để bật `mod_rewrite` khác nhau tùy thuộc vào hệ điều hành của bạn. Bạn có thể kích hoạt nó bằng cách chạy `sudo a2enmod rewrite` trên Ubuntu. `mod_rewrite` được bật theo mặc định trên CentOS. Đừng quên khởi động lại Apache sau khi thực hiện các sửa đổi! + +### Nginx + +Flarum bao gồm một tệp `.nginx.conf` - hãy đảm bảo rằng nó đã được tải lên một cách chính xác. Sau đó, giả sử bạn có một trang web PHP được thiết lập trong Nginx, hãy thêm phần sau vào khối cấu hình máy chủ của bạn: + +```nginx +include /path/to/flarum/.nginx.conf; +``` + +### Caddy + +Caddy yêu cầu một cấu hình rất đơn giản để Flarum hoạt động bình thường. Lưu ý rằng bạn nên thay thế URL bằng URL của riêng bạn và đường dẫn bằng đường dẫn đến thư mục `public` của riêng bạn. Nếu bạn đang sử dụng một phiên bản PHP khác, bạn cũng cần thay đổi đường dẫn `fastcgi` để trỏ đến đúng ổ cắm hoặc URL cài đặt PHP của bạn. + +``` +www.example.com { + root * /var/www/flarum/public + php_fastcgi unix//var/run/php/php7.4-fpm.sock + header /assets/* { + +Cache-Control "public, must-revalidate, proxy-revalidate" + +Cache-Control "max-age=25000" + Pragma "public" + } + file_server +} +``` +## Quyền sở hữu thư mục + +Trong khi cài đặt, Flarum có thể yêu cầu bạn làm cho một số thư mục có thể ghi được. Các hệ điều hành hiện nay thường có nhiều tài khoản, có nghĩa là tài khoản bạn đăng nhập không giống với tài khoản mà Flarum đang chạy. Tài khoản mà Flarum đang chạy PHẢI có quyền đọc + ghi đối với: + +- Thư mục cài đặt gốc, vì vậy Flarum có thể chỉnh sửa `config.php`. +- Thư mục `storage`, vì vậy Flarum có thể chỉnh sửa nhật ký và lưu trữ dữ liệu đã lưu trong bộ nhớ cache. +- Thư mục `asset` để các biểu trưng và hình đại diện có thể được tải lên hệ thống tệp. + +Các tiện ích mở rộng có thể yêu cầu các thư mục khác, vì vậy bạn có thể muốn cấp đệ quy quyền ghi vào toàn bộ thư mục cài đặt gốc Flarum. + +Có một số lệnh bạn sẽ cần chạy để thiết lập quyền đối với tệp. Xin lưu ý rằng nếu cài đặt của bạn không hiển thị cảnh báo sau khi thực hiện chỉ một số trong số này, bạn không cần phải chạy phần còn lại. + +Đầu tiên, bạn cần cho phép quyền ghi vào thư mục. Trên Linux: + +```bash +chmod 775 -R /path/to/directory +``` + +Nếu vẫn chưa được, bạn có thể cần kiểm tra xem các tệp của mình có thuộc sở hữu của đúng nhóm và người dùng hay không. Theo mặc định, trong hầu hết các bản phân phối Linux, `www-data` là nhóm và người dùng mà cả PHP và máy chủ web đều hoạt động theo. Bạn sẽ cần phải xem xét các chi tiết cụ thể của bản phân phối và thiết lập máy chủ web của mình để đảm bảo. Bạn có thể thay đổi quyền sở hữu thư mục trong hầu hết các hệ điều hành Linux bằng cách chạy: + +```bash +chown -R www-data: www-data /path/to/directory +``` + +Với `www-data` được thay đổi thành thứ khác nếu một người dùng/nhóm khác được sử dụng cho máy chủ web của bạn. + +Ngoài ra, bạn sẽ cần đảm bảo rằng người dùng CLI của mình (người dùng mà bạn đăng nhập vào thiết bị đầu cuối) có quyền sở hữu, để bạn có thể cài đặt các tiện ích mở rộng và quản lý cài đặt Flarum thông qua CLI. Để thực hiện việc này, hãy thêm người dùng hiện tại của bạn (`whoami`) vào nhóm máy chủ web (thường là `www-data`) qua `usermod -a -G www-data YOUR_USERNAME`. Bạn có thể sẽ phải đăng xuất và đăng nhập lại để thay đổi này có hiệu lực. + +Cuối cùng, nếu điều đó không hiệu quả, bạn có thể cần phải cấu hình [SELinux](https://www.redhat.com/en/topics/linux/what-is-selinux) để cho phép máy chủ web để ghi vào thư mục. Để làm như vậy, hãy chạy: + +```bash +chcon -R -t httpd_sys_rw_content_t /path/to/directory +``` + +Để tìm hiểu thêm về các lệnh này cũng như các quyền và quyền sở hữu tệp trên Linux, hãy đọc [hướng dẫn này](https://www.thegeekdiary.com/understanding-basic-file-permissions-and-ownership-in-linux/). Nếu bạn đang thiết lập Flarum trên Windows, bạn có thể tìm thấy câu trả lời cho [câu hỏi về Người dùng siêu cấp này](https://superuser.com/questions/106181/equivalent-of-chmod-to-change-file-permissions-in-windows) hữu ích. + +:::caution Môi trường có thể khác nhau + +Môi trường của bạn có thể khác với tài liệu được cung cấp, vui lòng tham khảo cấu hình máy chủ web của bạn hoặc nhà cung cấp dịch vụ lưu trữ web để biết người dùng và nhóm thích hợp mà PHP và máy chủ web hoạt động. + +::: + +:::danger Không bao giờ sử dụng quyền 777 + +Bạn không bao giờ được đặt bất kỳ thư mục hoặc tệp nào ở cấp độ quyền `777`, vì cấp độ quyền này cho phép bất kỳ ai cũng có thể truy cập nội dung của thư mục và tệp bất kể người dùng hoặc nhóm. + +::: + +## Tuỳ chỉnh đường dẫn + +Theo mặc định, cấu trúc thư mục của Flarum bao gồm thư mục `public` chỉ chứa các tệp có thể truy cập công khai. Đây là phương pháp tốt nhất về bảo mật, đảm bảo rằng tất cả các tệp mã nguồn nhạy cảm hoàn toàn không thể truy cập được từ web gốc. + +Tuy nhiên, nếu bạn muốn lưu trữ Flarum trong một thư mục con (như `yourite.com/forum`) hoặc nếu máy chủ của bạn không cấp cho bạn quyền kiểm soát webroot của mình (bạn đang mắc kẹt với một cái gì đó như `public_html` hoặc `htdocs`), bạn có thể thiết lập Flarum mà không cần thư mục `public`. + +If you intend to install Flarum using one of the archives, you can simply use the `no-public-dir` (Public Path = No) [archives](#installing-by-unpacking-an-archive) and skip the rest of this section. If you're installing via Composer, you'll need to follow the instructions below. + +Đơn giản chỉ cần di chuyển tất cả các tệp bên trong thư mục `public` (bao gồm cả `.htaccess`) vào thư mục bạn muốn chạy Flarum. Sau đó, chỉnh sửa `.htaccess` và bỏ ghi chú dòng 9-15 để bảo vệ các tài nguyên nhạy cảm. Đối với Nginx, bỏ ghi chú dòng 8-11 của `.nginx.conf`. + +Bạn cũng sẽ cần chỉnh sửa tệp `index.php` và thay đổi dòng sau: + +```php +$site = require './site.php'; +``` + + Chỉnh sửa `site.php` và cập nhật các đường dẫn trong các dòng sau để phản ánh cấu trúc thư mục mới của bạn: + +```php +'base' => __DIR__, +'public' => __DIR__, +'storage' => __DIR__.'/storage', +``` + +Cuối cùng, kiểm tra `config.php` và đảm bảo giá trị `url` là chính xác. + +## Nhập dữ liệu + +Nếu bạn có một cộng đồng hiện có và không muốn bắt đầu lại từ đầu, bạn có thể nhập dữ liệu hiện có của mình vào Flarum. Trong khi chưa có nhà nhập khẩu chính thức, cộng đồng đã có một số trình chuyển dữ liệu không chính thức: + +* [FluxBB](https://discuss.flarum.org/d/3867-fluxbb-to-flarum-migration-tool) +* [MyBB](https://discuss.flarum.org/d/5506-mybb-migrate-script) +* [phpBB](https://discuss.flarum.org/d/1117-phpbb-migrate-script-updated-for-beta-5) +* [SMF2](https://github.com/ItalianSpaceAstronauticsAssociation/smf2_to_flarum) + +Chúng có thể được sử dụng cho các phần mềm diễn đàn khác bằng cách chuyển sang phpBB trước, sau đó đến Flarum. Xin lưu ý rằng chúng tôi không thể đảm bảo rằng những điều này sẽ hoạt động cũng như không thể cung cấp hỗ trợ cho chúng. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/README.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/README.md new file mode 100644 index 000000000..98ab9ea30 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/README.md @@ -0,0 +1,7 @@ +--- +slug: '/internal' +--- + +# Tài liệu nhóm nội bộ + +Đây là phần tài liệu mới, nơi chúng tôi sẽ đăng một số tài liệu được nhóm Flarum sử dụng nội bộ. Chúng tôi đang bắt đầu phần này để cung cấp cho cộng đồng sự minh bạch về cách thức hoạt động của Flarum và giúp những người hy vọng đóng góp cho Flarum. \ No newline at end of file diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md new file mode 100644 index 000000000..555e7977c --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md @@ -0,0 +1,28 @@ +# Bundled Extensions Policy + +This document is to assist in deciding what core features should be bundled or maintained by the Flarum project team. + +Understand that Flarum aims to have a lean and efficient team. To guarantee a transparent workload, we intentionally have a "this could be an extension" mentality. The acronym D.O.R.C. spells out our decision-making process. + +- **Density**: prevent bloating Flarum so that it becomes a burden to install on shared hosting plans with limited space. +- **Opinionatedness**: no extensions should be bundled that is only useful by only a limited amount of communities or on specific hosting environments. +- **Responsibility**: extensions that could easily be maintained by others should be maintained by others. +- **Complexity**: extensions that are complex in terms of design, frontend or backend code should not be a responsibility of the Flarum project team. + +### Density + +To prevent the installation size of Flarum from continuously increasing we need to protect it from extensions that bloat it. We should ship extensions with Flarum that, for instance, have kilobytes in media files. + +### Opinionatedness + +Our goal is to allow installation of Flarum, in its vanilla form, by any community on any hosting environment. This includes shared hosting environment as well. + +Releasing Flarum with extensions that add functionality specific to cloud based (AWS) installations or for corporate support communities, as such, is unwanted. + +### Responsibility + +Protecting the time of the project team is key. To do so we should empower the ecosystem in building extensions that it needs. Therefor we distance ourselves from the responsibility of building every and all extensions. The responsibility of extension development is held primarily by our community. + +### Complexity + +Complex extensions require a vast amount of time, not just for development, but also documentation and support. To protect the lean and efficient principles of the team, we will not take ownership of extensions that add this complexity. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md new file mode 100644 index 000000000..c2287d5fc --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md @@ -0,0 +1,87 @@ +# Extension Manager +This contains an explanation of how the extension manager works and what it has to offer. + +slightly outdated: see [the extensions guide for more](/extensions.md). + +## Nội dung +* Cài đặt, Cập nhật và Xoá tiện ích mở rộng. +* [Kiểm tra bản cập nhật](#checking-for-updates). +* [Cập nhật toàn bộ Flarum](#global-flarum-updates). +* [Cập nhật từng gói Flarum nhỏ](#patch-minor-flarum-updates). +* [Cập nhật chính Flarum](#major-flarum-updates). +* [Cập nhật Flarum (toàn bộ, từng cái, chính)](#flarum-updates-global-minor-major). +* [Nền tác vụ](#background-tasks). + +## Yêu cầu +Có một số trở ngại cần được lưu ý trước khi sử dụng. + +### Quyền đối với tệp +User web cần có quyền đọc và ghi các tệp và thư mục như: `vendor`, `composer.json`, `composer.lock` và `storage`. Ngay bây giờ, một cảnh báo sẽ hiển thị khi trường hợp này không xảy ra, điều này tốt nhất nên được thay đổi để chỉ đề cập đến các tệp/thư mục thiếu quyền thay vì tất cả. + +![flarum lan_admin (3)](https://user-images.githubusercontent.com/20267363/135268536-f79d42ab-6e05-4e41-b2ab-d95ec7a8b021.png) + +### Đường dẫn kho lưu trữ +Trong môi trường phát triển (và sản xuất trong các tình huống hiếm gặp) nên có một kho lưu trữ đường dẫn đến một thư mục chứa các gói (chủ yếu là dev), đường dẫn đến thư mục này phải được thay đổi thành một đường dẫn tuyệt đối, nếu không trình soạn thảo sẽ gặp khó khăn khi chạy bất kỳ lệnh nào. Additionally the path repository by default has higher priority, so requiring an extension that exists in that repository will probably fail, unless a `*@dev` constraint is specified, in which case the extension manager should not be used for dev purposes anyway. + +There is currently now hint of any of this in the extension manager UI. + +## Các hành động phổ biến +Mỗi một trong số các tính năng được liệt kê ở trên về cơ bản là một hoặc hai lệnh của Composer, và có những hành động/hành vi chung giữa tất cả chúng. + +* Hạn chế quyền truy cập vào quản trị viên. +* Xác thực tên gói được cung cấp hoặc id phần mở rộng nếu được cung cấp. +* Lỗi nếu cài đặt tiện ích mở rộng hiện có, cập nhật hoặc xóa tiện ích mở rộng không hiện có ... vv +* Đang chạy lệnh [tự động ghi lại nhật ký đầu ra](#command-output-logging). +* [Lỗi do lỗi câu lệnh](#command-failure). +* Phái một sự kiện. +* Nếu đang chạy bản cập nhật: + + Xóa bộ nhớ cache. + + Chạy di chuyển. + + Xuất bản nội dung. + + Chạy kiểm tra cập nhật và ghi lại bất kỳ tiện ích mở rộng nào không cập nhật lên phiên bản mới nhất của chúng trong quá trình cập nhật. + +### Ghi nhật ký lệnh đầu ra +Xem xét điều này vẫn đang thử nghiệm và đặc biệt là để hỗ trợ dễ dàng hơn, mỗi đầu ra lệnh được ghi vào `storage/logs/composer` giống như các bản ghi lỗi Flarum, cho phép quay lại và xem điều gì đã xảy ra trong một lệnh chấp hành. + +### Lệnh thất bại +Khi một lệnh Composer không thành công (được mã thoát nhận dạng), một ngoại lệ được đưa ra có chứa lý do ngoại lệ đó đoán ra dựa trên văn bản đầu ra của lệnh. Các nguyên nhân được phỏng đoán hiển thị thành các thông báo cảnh báo giải thích thích hợp trên giao diện người dùng. + +## Kiểm tra các bản cập nhật +Thao tác này thực thi lệnh `composer outdated -D --format json` kiểm tra các bản cập nhật của các gói được yêu cầu trực tiếp trong thư mục gốc `composer.json` và xuất ra kết quả ở định dạng JSON. Chỉ những gói được đánh dấu là `semver-safe-update` và `update-could` bởi Composer mới được hiển thị. + +Thông tin về lần kiểm tra cập nhật cuối cùng được lưu vào cài đặt JSON. + +![flarum lan_admin (4)](https://user-images.githubusercontent.com/20267363/135272032-9de37599-b364-4e42-b234-1113135eaa83.png) + +## Cập nhật toàn bộ Flarum +Chỉ cần chạy lệnh `command update --prefer-dist --no-dev -a --with-all-dependencies`, hữu ích để cập nhật tất cả các gói. + +## Cập nhật Flarum bản vá lỗi nhỏ +Điều này thay đổi trực tiếp các phiên bản gói được yêu cầu thành `*` và sau đó thực thi lệnh `command update --prefer-dist --no-dev -a --with-all-dependencies`. + +![flarum lan_admin (5)](https://user-images.githubusercontent.com/20267363/135276114-ae438c2f-4122-45bd-b32f-690de3b56e25.png) + +## Cập nhật Flarum chính +Điều này thay đổi trực tiếp các phiên bản gói được yêu cầu thành `*`, thay đổi cốt lõi thành yêu cầu phiên bản chính mới nhất và sau đó thực hiện lệnh tương tự ở trên. Khi thất bại, có thể đoán chính xác rằng một số tiện ích mở rộng không tương thích với phiên bản chính mới, các chi tiết ngoại lệ sẽ bao gồm một loạt các tên gói tiện ích mở rộng không tương thích và nó sẽ được hiển thị trong giao diện người dùng, với khả năng chạy `composer why-not flarum/core 2.0` để biết thêm chi tiết. + +![cập nhật giao diện người dùng chính](https://user-images.githubusercontent.com/20267363/143277865-8323fa9a-c80f-4015-baca-fce4d2b5d585.png) + +## Cập nhật Flarum (toàn bộ, phụ, chính) +Thông tin về các bản cập nhật cuối cùng đã chạy được lưu trong cài đặt `last_update_run` JSON, có thể chứa một loạt các tên gói phần mở rộng không cập nhật lên phiên bản mới nhất của chúng trong quá trình này, điều này được hiển thị trong giao diện người dùng dưới dạng các nút biểu tượng cảnh báo trên các mục tiện ích mở rộng, nhấp vào chúng sẽ thực hiện `composer why-not`, hiển thị chi tiết về lỗi trong một phương thức. + +![Giao diện người dùng với danh sách các tiện ích mở rộng chứa các nút biểu tượng cảnh báo](https://user-images.githubusercontent.com/20267363/143278774-6fada0da-dead-474b-8dfa-feda5021134f.png) ![Giao diện người dùng với phương thức hiển thị chi tiết](https://user-images.githubusercontent.com/20267363/143278786-d283db62-de96-4019-954e-932d0d6eac15.png) + +## Nhiệm vụ nền +Để giải quyết các vấn đề về thời gian chờ, các lệnh của trình soạn nhạc cũng có thể chạy trên nền bằng cách sử dụng hàng đợi. Người dùng có thể được hướng tới [Blomstra's Database Queue Implementation](https://discuss.flarum.org/d/28151-database-queue-the-simplest-queue-even-for-shared-hosting) như một giải pháp hàng đợi cơ bản. Nó chứa các hướng dẫn về cách kích hoạt hàng đợi thông qua một công việc cron. + +:::danger Phiên bản quy trình PHP Job Cron + +Các máy chủ chia sẻ thường có phiên bản php thấp được sử dụng trong SSH, người dùng phải được chỉ ra thực tế rằng họ phải đảm bảo quy trình php là phiên bản tương thích với Flarum. Bằng cách kiểm tra thủ công hoặc bằng cách hỏi máy chủ của họ. + +::: + +![Extension Manager Queue Table Preview](/en/img/extension-manager-queue.png) + +## TODO +- Hãy thử trên dịch vụ lưu trữ được chia sẻ. +- Giải thích tốt hơn trên giao diện người dùng về các tác vụ nền. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md new file mode 100644 index 000000000..067e2809f --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md @@ -0,0 +1,38 @@ +# PR Merging Policy + +Technical contributions to the Flarum source code go through a review process. Over the years we have tuned this process based on our experiences, our targeted development speed and availability. + +## What makes a great Pull Request? + +Great pull requests: + +- Have the [Pull Request template](https://github.com/flarum/.github/blob/main/PULL_REQUEST_TEMPLATE.md) filled out completely when opening a pull request. +- Do not combine different changes. Although tempting, don't change formatting of unrelated code. Stick to the one feature or change you wish to contribute. +- Have a related issue where the technical implementation has been agreed upon by the core team, or has been approved on by the core team through discussion on the official forums or other channels like Discord. +- Clearly explain the need for the change and list the areas where the pull request requires discussion. + +## Implementation Review Criteria + +- Adheres to our conventions or can be patched up easily after merging, follows proper code style. +- Are there any implementation details that could be done better through alternate technologies/technical approaches? +- Does not touch any lines outside of the intended changes, eg through formatting or compilation. +- If the changes are to code intended as a public API, has a proper doc block been included? + +## Merge Time! + +If all the checks in the template are met, **any** core developer may merge this PR. If the PR is authored by a core developer, they should probably be the ones to merge it. + +- Merging: + - GitHub offers several ways to merge a PR. Choose between the following strategies: + - **Merge** when the PR branch consists of atomic, well-described commits that are nice to have in the version history. + - **Squash** when lots of cleanup commits have accumulated. Please make sure to follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) spec for the squash commit. We usually find several commits from bots like StyleCI in these prefabricated commit messages, their commit messages should be removed. + +- After merging: + - Assign the related issue (if none exists, the pull request itself, but never both) to the appropriate milestone. + - Close all relevant issues (*if* they are closed completely). + - Regressions should be labeled as such and removed from the project board and milestone after merging. + - Check for follow-up tasks: + - Merge related PRs (language files, extensions, documentations). + - Documentation updates. + - Create issues for further follow-up tasks, if necessary. + diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/merging.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/merging.md new file mode 100644 index 000000000..0408b1bee --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/merging.md @@ -0,0 +1,29 @@ +# PR Merging Workflow + + +## Implementation Review Criteria + +- Adheres to our conventions or can be patched up easily after merging, follows proper code style. +- Are there any implementation details that could be done better through alternate technologies/technical approaches? +- Does not touch any lines outside of the intended changes, eg through formatting or compilation. +- If the changes are to code intended as a public API, has a proper doc block been included? + +## Merge Time! + +If all of the checks in the template are met, **any** core developer may merge this PR. If the PR is authored by a core developer, they should probably be the ones to merge it. + +- Merging: + - GitHub offers several ways to merge a PR. Choose between the following strategies: + - **Merge** when the PR branch consists of atomic, well-described commits that are nice to have in the version history. + - **Squash** when lots of cleanup commits have accumulated. Please make sure to follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) spec for the squash commit. + +- After merging: + - Make sure the *issue* (if none exists, the PR - but not both) belongs to the appropriate milestone and project board. + - PRs in extensions cannot be assigned to core milestones, so create a core issue that references it and add it to the milestone. + - Close all relevant issues (*if* they are closed completely). + - Regressions should be labeled as such and removed from the project board and milestone after merging. + - Check for follow-up tasks: + - Merge related PRs (language files, extensions, documentations). + - Documentation updates. + - Create issues for further follow-up tasks, if necessary. + diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md new file mode 100644 index 000000000..63aa29268 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md @@ -0,0 +1,89 @@ +# Trình quản lý gói +Dưới đây sẽ giải thích về cách hoạt động của Trình quản lý gói và những gì nó có thể làm được. + +## Nội dung +* Cài đặt, Cập nhật và Xoá tiện ích mở rộng. +* [Kiểm tra bản cập nhật](#checking-for-updates). +* [Cập nhật toàn bộ Flarum](#global-flarum-updates). +* [Cập nhật từng gói Flarum nhỏ](#patch-minor-flarum-updates). +* [Cập nhật chính Flarum](#major-flarum-updates). +* [Cập nhật Flarum (toàn bộ, từng cái, chính)](#flarum-updates-global-minor-major). +* [Nền tác vụ](#background-tasks). + +## Yêu cầu +Có một số trở ngại cần được lưu ý trước khi sử dụng. + +### Quyền đối với tệp +User web cần có quyền đọc và ghi các tệp và thư mục như: `vendor`, `composer.json`, `composer.lock` và `storage`. Ngay bây giờ, một cảnh báo sẽ hiển thị khi trường hợp này không xảy ra, điều này tốt nhất nên được thay đổi để chỉ đề cập đến các tệp/thư mục thiếu quyền thay vì tất cả. + +![flarum lan_admin (3)](https://user-images.githubusercontent.com/20267363/135268536-f79d42ab-6e05-4e41-b2ab-d95ec7a8b021.png) + +### Đường dẫn kho lưu trữ +Trong môi trường phát triển (và sản xuất trong các tình huống hiếm gặp) nên có một kho lưu trữ đường dẫn đến một thư mục chứa các gói (chủ yếu là dev), đường dẫn đến thư mục này phải được thay đổi thành một đường dẫn tuyệt đối, nếu không trình soạn thảo sẽ gặp khó khăn khi chạy bất kỳ lệnh nào. Ngoài ra, kho lưu trữ đường dẫn theo mặc định có mức độ ưu tiên cao hơn, vì vậy việc yêu cầu một phần mở rộng tồn tại trong kho lưu trữ đó có thể sẽ không thành công, trừ khi một ràng buộc `*@dev` được chỉ định, trong trường hợp đó, trình quản lý gói không được sử dụng cho các mục đích của nhà phát triển dù sao. + +Hiện tại có gợi ý về bất kỳ điều này trong giao diện người dùng của trình quản lý gói. + +## Các hành động phổ biến +Mỗi một trong số các tính năng được liệt kê ở trên về cơ bản là một hoặc hai lệnh của Composer, và có những hành động/hành vi chung giữa tất cả chúng. + +* Hạn chế quyền truy cập vào quản trị viên. +* Xác thực tên gói được cung cấp hoặc id phần mở rộng nếu được cung cấp. +* Lỗi nếu cài đặt tiện ích mở rộng hiện có, cập nhật hoặc xóa tiện ích mở rộng không hiện có ... vv +* Đang chạy lệnh [tự động ghi lại nhật ký đầu ra](#command-output-logging). +* [Lỗi do lỗi câu lệnh](#command-failure). +* Phái một sự kiện. +* Nếu đang chạy bản cập nhật: + + Xóa bộ nhớ cache. + + Chạy di chuyển. + + Xuất bản nội dung. + + Chạy kiểm tra cập nhật và ghi lại bất kỳ tiện ích mở rộng nào không cập nhật lên phiên bản mới nhất của chúng trong quá trình cập nhật. + +### Ghi nhật ký lệnh đầu ra +Xem xét điều này vẫn đang thử nghiệm và đặc biệt là để hỗ trợ dễ dàng hơn, mỗi đầu ra lệnh được ghi vào `storage/logs/composer` giống như các bản ghi lỗi Flarum, cho phép quay lại và xem điều gì đã xảy ra trong một lệnh chấp hành. + +### Lệnh thất bại +Khi một lệnh Composer không thành công (được mã thoát nhận dạng), một ngoại lệ được đưa ra có chứa lý do ngoại lệ đó đoán ra dựa trên văn bản đầu ra của lệnh. Các nguyên nhân được phỏng đoán hiển thị thành các thông báo cảnh báo giải thích thích hợp trên giao diện người dùng. + +## Kiểm tra các bản cập nhật +Thao tác này thực thi lệnh `composer outdated -D --format json` kiểm tra các bản cập nhật của các gói được yêu cầu trực tiếp trong thư mục gốc `composer.json` và xuất ra kết quả ở định dạng JSON. Chỉ những gói được đánh dấu là `semver-safe-update` và `update-could` bởi Composer mới được hiển thị. + +Thông tin về lần kiểm tra cập nhật cuối cùng được lưu vào cài đặt JSON. + +![flarum lan_admin (4)](https://user-images.githubusercontent.com/20267363/135272032-9de37599-b364-4e42-b234-1113135eaa83.png) + +## Cập nhật toàn bộ Flarum +Chỉ cần chạy lệnh `command update --prefer-dist --no-dev -a --with-all-dependencies`, hữu ích để cập nhật tất cả các gói. + +## Cập nhật Flarum bản vá lỗi nhỏ +Điều này thay đổi trực tiếp các phiên bản gói được yêu cầu thành `*` và sau đó thực thi lệnh `command update --prefer-dist --no-dev -a --with-all-dependencies`. + +![flarum lan_admin (5)](https://user-images.githubusercontent.com/20267363/135276114-ae438c2f-4122-45bd-b32f-690de3b56e25.png) + +## Cập nhật Flarum chính +Điều này thay đổi trực tiếp các phiên bản gói được yêu cầu thành `*`, thay đổi cốt lõi thành yêu cầu phiên bản chính mới nhất và sau đó thực hiện lệnh tương tự ở trên. Khi thất bại, có thể đoán chính xác rằng một số tiện ích mở rộng không tương thích với phiên bản chính mới, các chi tiết ngoại lệ sẽ bao gồm một loạt các tên gói tiện ích mở rộng không tương thích và nó sẽ được hiển thị trong giao diện người dùng, với khả năng chạy `composer why-not flarum/core 2.0` để biết thêm chi tiết. + +![cập nhật giao diện người dùng chính](https://user-images.githubusercontent.com/20267363/143277865-8323fa9a-c80f-4015-baca-fce4d2b5d585.png) + +## Cập nhật Flarum (toàn bộ, phụ, chính) +Thông tin về các bản cập nhật cuối cùng đã chạy được lưu trong cài đặt `last_update_run` JSON, có thể chứa một loạt các tên gói phần mở rộng không cập nhật lên phiên bản mới nhất của chúng trong quá trình này, điều này được hiển thị trong giao diện người dùng dưới dạng các nút biểu tượng cảnh báo trên các mục tiện ích mở rộng, nhấp vào chúng sẽ thực hiện `composer why-not`, hiển thị chi tiết về lỗi trong một phương thức. + +![Giao diện người dùng với danh sách các tiện ích mở rộng chứa các nút biểu tượng cảnh báo](https://user-images.githubusercontent.com/20267363/143278774-6fada0da-dead-474b-8dfa-feda5021134f.png) ![Giao diện người dùng với phương thức hiển thị chi tiết](https://user-images.githubusercontent.com/20267363/143278786-d283db62-de96-4019-954e-932d0d6eac15.png) + +## Nhiệm vụ nền +Để giải quyết các vấn đề về thời gian chờ, các lệnh của trình soạn nhạc cũng có thể chạy trên nền bằng cách sử dụng hàng đợi. Người dùng có thể được hướng tới [Blomstra's Database Queue Implementation](https://discuss.flarum.org/d/28151-database-queue-the-simplest-queue-even-for-shared-hosting) như một giải pháp hàng đợi cơ bản. Nó chứa các hướng dẫn về cách kích hoạt hàng đợi thông qua một công việc cron. + +:::danger Phiên bản quy trình PHP Job Cron + +Các máy chủ chia sẻ thường có phiên bản php thấp được sử dụng trong SSH, người dùng phải được chỉ ra thực tế rằng họ phải đảm bảo quy trình php là phiên bản tương thích với Flarum. Bằng cách kiểm tra thủ công hoặc bằng cách hỏi máy chủ của họ. + +::: + +![Xem trước bảng xếp hàng của trình quản lý gói](/en/img/package-manager-queue.png) + +## TODO +- Hãy thử trên dịch vụ lưu trữ được chia sẻ. +- Lệnh của Composer không được trùng lặp. +- Mã TODOs. +- Giải thích tốt hơn trên giao diện người dùng về các tác vụ nền. +- Hãy xem xét một tình huống trong đó chúng tôi đang cập nhật tiện ích mở rộng không phải là phần phụ thuộc bắt buộc gốc, chẳng hạn như gói. +- Chạy một tác vụ nền tại một thời điểm, ngăn người dùng kích hoạt nhiều tác vụ. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/languages.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/languages.md new file mode 100644 index 000000000..bc0a73685 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/languages.md @@ -0,0 +1,29 @@ +# Ngôn ngữ + +Thật dễ dàng để thêm một ngôn ngữ mới vào cài đặt Flarum cơ bản của bạn. Chỉ cần làm theo hướng dẫn bên dưới để tải xuống và cài đặt gói ngôn ngữ bạn chọn. + +Khi bạn đã thêm gói ngôn ngữ, bạn có thể [ đặt nó làm ngôn ngữ mặc định ](#setting-the-default-language) cho diễn đàn của mình. Và nếu bạn thấy mình không cần một trong các gói ngôn ngữ đã cài đặt, bạn luôn có thể [ tắt nó ](#disabling-a-language-pack). Nếu bạn đang sử dụng bất kỳ tiện ích mở rộng nào của bên thứ ba, hãy nhớ [ đọc phần này ](#third-party-extensions) trước khi bắt đầu. + +## Cài đặt Gói ngôn ngữ + +Để bắt đầu, hãy truy cập thẻ [Extensions > Languages](https://discuss.flarum.org/t/languages) tại trang Cộng đồng Flarum và tìm gói ngôn ngữ mà bạn muốn cài đặt. + +Gói ngôn ngữ được cài đặt giống như [ phần mở rộng ](extensions.md). Ngôn ngữ sẽ xuất hiện trong trang ** Tiện ích mở rộng ** của giao diện quản trị và bạn có thể bật ngôn ngữ đó ở đó. + +Đó là tất cả để có nó! Giờ đây, bạn có thể sử dụng công cụ chọn ngôn ngữ trong tiêu đề trang web của mình để chuyển hiển thị của diễn đàn sang ngôn ngữ mới. + +## Thiết lập ngôn ngữ mặc định + +Sau khi bạn đã cài đặt gói ngôn ngữ và đảm bảo rằng nó đang hoạt động, bạn có thể muốn đặt gói này làm ngôn ngữ mặc định cho người dùng và khách mới. Bạn có thể làm điều đó trên trang **Cơ bản** của giao diện quản trị viên. + +## Vô hiệu hoá Gói ngôn ngữ + +Nếu bạn quyết định rằng bạn không cần phải hỗ trợ một ngôn ngữ nhất định, thì bạn có thể tắt nó đi. Chỉ cần tìm gói ngôn ngữ trong trang **Tiện ích mở rộng** của giao diện quản trị viên và tắt nó. + +Việc tắt một ngôn ngữ có thể hữu ích nếu bạn đang chạy một trang web đơn ngữ và không muốn bộ chọn ngôn ngữ xuất hiện trong tiêu đề trang web. Bộ chọn ngôn ngữ bị ẩn khi chỉ một ngôn ngữ được bật. + +## Cộng đồng Tiện ích mở rộng + +Mặc dù các gói ngôn ngữ được tải xuống từ trang web Cộng đồng Flarum nói chung sẽ bao gồm bản dịch cho tất cả các tiện ích mở rộng đi kèm với Flarum, chúng _sẽ không_ như một quy tắc bao gồm bất kỳ tiện ích mở rộng cộng đồng nào mà bạn có thể có Cài đặt. Việc cung cấp và duy trì bản dịch cho các tiện ích mở rộng của họ là tùy thuộc vào các nhà phát triển. + +Vì vậy, trước khi cài đặt tiện ích mở rộng cộng đồng, bạn nên kiểm tra để đảm bảo rằng nó bao gồm các bản dịch cho từng gói ngôn ngữ mà bạn đã cài đặt. Nếu bạn nhận thấy rằng tiện ích mở rộng không hỗ trợ ngôn ngữ bạn cần, vui lòng liên hệ trực tiếp với nhà phát triển và sắp xếp để được bổ sung các bản dịch cần thiết. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/mail.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/mail.md new file mode 100644 index 000000000..7aee74e87 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/mail.md @@ -0,0 +1,29 @@ +# Cấu hình Email + +Bất kỳ cộng đồng nào cũng cần gửi email để cho phép xác minh email, đặt lại mật khẩu, thông báo và các giao tiếp khác tới người dùng. Định cấu hình diễn đàn của bạn để gửi email nên là một trong những bước đầu tiên của bạn với tư cách là quản trị viên: cấu hình không chính xác sẽ gây ra lỗi khi người dùng cố gắng đăng ký. + +## Trình điều khiển có sẵn + +Flarum cung cấp một số trình điều khiển theo mặc định, chúng được liệt kê và giải thích bên dưới. Các nhà phát triển cũng có thể thêm [trình điều khiển thư tùy chỉnh thông qua các tiện ích mở rộng](extend/mail.md). + +### SMTP + +Đây có lẽ là trình điều khiển email được sử dụng phổ biến nhất, cho phép bạn định cấu hình máy chủ lưu trữ, cổng / mã hóa, tên người dùng và mật khẩu cho dịch vụ SMTP bên ngoài. Xin lưu ý rằng trường mã hóa yêu cầu `ssl` hoặc `tls`. + +### Mail + +Trình điều khiển `mail` sẽ cố gắng sử dụng hệ thống email sendmail/postfix có trong nhiều máy chủ lưu trữ. Bạn phải cài đặt đúng cách và định cấu hình sendmail trên máy chủ của mình để nó hoạt động. + +### Mailgun + +Trình điều khiển này sử dụng tài khoản [Mailgun](https://www.mailgun.com/) của bạn để gửi email. Bạn sẽ cần một khóa bí mật, cũng như miền và khu vực từ cấu hình mailgun của bạn. + +Để sử dụng trình điều khiển mailgun, bạn sẽ cần cài đặt gói trình soạn nhạc Guzzle (một ứng dụng khách PHP HTTP). Bạn có thể thực hiện việc này bằng cách chạy `composer require guzzlehttp/guzzle:^6.0|^7.0` trong thư mục gốc của cài đặt Flarum của bạn. + +### Nhật ký + +Trình điều khiển thư nhật ký KHÔNG GỬI MAIL, và chủ yếu được sử dụng bởi các nhà phát triển. Nó ghi nội dung của bất kỳ email nào vào tệp nhật ký trong `FLARUM_ROOT_DIRECTORY/storage/logs`. + +## Thử nghiệm Email + +Khi bạn đã lưu cấu hình email, bạn có thể nhấp vào nút "Gửi Thư Kiểm tra" trên trang Thư của bảng điều khiển quản trị để đảm bảo cấu hình của bạn hoạt động. Khi bạn đã lưu email cấu hình, bạn có thể chạm vào nút "Gửi Thư Kiểm tra" trên trang Thư của người quản lý bảng để đảm bảo cấu hình của bạn hoạt động. Đảm bảo kiểm tra thư rác của bạn nếu không có lỗi, nhưng không có gì hiển thị trong hộp thư đến của bạn. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/releases.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/releases.md new file mode 100644 index 000000000..26f3474ca --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/releases.md @@ -0,0 +1,15 @@ +# Ghi chú phát hành + + + + +Các ghi chú phát hành để thể tìm thấy trong [Cộng đồng Flarum](https://discuss.flarum.org/t/blog?sort=newest). diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/rest-api.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/rest-api.md new file mode 100644 index 000000000..79552d7d8 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/rest-api.md @@ -0,0 +1,375 @@ +# Sử dụng REST API + +Flarum có sẵn API REST được ứng dụng một trang sử dụng nhưng cũng có sẵn cho các tập lệnh bên ngoài. + +API tuân theo các phương pháp hay nhất được xác định bởi đặc tả [JSON: API](https://jsonapi.org/). + +:::info + +Để mở rộng REST API với các điểm cuối mới, hãy xem [API và Luồng dữ liệu](extend/api.md) trong tài liệu dành cho nhà phát triển. + +::: + +## Xác thực + +Ứng dụng trang đơn sử dụng cookie phiên để xác thực dựa trên API. Các tập lệnh bên ngoài có thể sử dụng xác thực không trạng thái bằng [Khóa API](#api-keys) hoặc [Mã token truy cập](#access-tokens). + +Điểm cuối `GET` có thể được sử dụng mà không cần xác thực. Chỉ nội dung hiển thị cho khách sẽ được trả lại. Các điểm cuối khác thường không thể được sử dụng mà không có xác thực vì [bảo vệ CSRF](#csrf-protection). + +### Khoá API + +Khóa API là cách chính để các tập lệnh, công cụ và tích hợp tương tác với Flarum. + +#### Tạo + +Hiện không có giao diện người dùng nào để quản lý Khóa API, nhưng chúng có thể được tạo theo cách thủ công trong bảng `api_keys` của cơ sở dữ liệu. + +Các thuộc tính sau có thể được điền: + +- `key`: Tạo một mã token dài duy nhất (khuyến nghị: chữ-số, 40 ký tự) và đặt nó ở đây, đây sẽ là mã thông báo được sử dụng trong header `Authorization`. +- `user_id`: Tùy chọn. Nếu được đặt, khóa chỉ có thể được sử dụng để hoạt động như một người dùng nhất định. + +Các thuộc tính còn lại hoặc được điền tự động hoặc hiện không được sử dụng: + +- `id`: Sẽ được điền bằng cách tăng tự động MySQL. +- `allow_ips`: Không được triển khai. +- `scopes`: Không được triển khai. +- `created_at`: Có thể được đặt thành bất kỳ ngày nào, nhưng có nghĩa là ngày tạo khóa. +- `last_activity_at`: Sẽ được cập nhật tự động khi mã thông báo được sử dụng. + +#### Sử dụng + +Đính kèm giá trị khóa của bạn vào mỗi yêu cầu API bằng header `Authorization`. Sau đó, cung cấp ID người dùng bạn muốn tương tác ở cuối header: + + Authorization: Token YOUR_API_KEY_VALUE; userId=1 + +Nếu giá trị `user_id` đã được đặt cho khóa trong cơ sở dữ liệu, thì `userId=` sẽ bị bỏ qua. Nếu không, nó có thể được đặt thành bất kỳ ID người dùng hợp lệ nào tồn tại trong cơ sở dữ liệu. + +### Mã token truy cập + +Mã token truy cập là mã token tồn tại trong thời gian ngắn thuộc về một người dùng cụ thể. + +Những mã token đó được sử dụng trong hậu trường cho các phiên cookie. Việc sử dụng chúng trong các yêu cầu API không trạng thái có tác dụng giống như một phiên thông thường. Hoạt động gần đây nhất của người dùng sẽ được cập nhật mỗi khi mã thông báo được sử dụng. + +#### Tạo + +Tất cả người dùng được phép tạo mã token truy cập. Để tạo mã token, hãy sử dụng điểm cuối `/api/token` với thông tin đăng nhập của người dùng của bạn: + +``` +POST /api/token HTTP/1.1 + +{ + "identification": "Toby", + "password": "pass7word" +} + +HTTP/1.1 200 OK + +{ + "token": "YACub2KLfe8mfmHPcUKtt6t2SMJOGPXnZbqhc3nX", + "userId": "1" +} +``` + +Hiện tại, 3 loại mã thông báo tồn tại, mặc dù chỉ có 2 loại có thể được tạo thông qua REST API. + +- Các mã token `session` hết hạn sau 1 giờ không hoạt động. Đây là loại mã token mặc định. +- Các mã token `session_remember` sẽ hết hạn sau 5 năm không hoạt động. Nó có thể được lấy bằng cách chỉ định `remember=1` trong các thuộc tính yêu cầu. +- Mã token `developer` không bao giờ hết hạn. Chúng chỉ có thể được tạo thủ công trong cơ sở dữ liệu vào lúc này. + +**Tất cả các mã token truy cập sẽ bị xóa khi người dùng đăng xuất** (điều này bao gồm các mã token của `developer`, mặc dù người ta đã lên kế hoạch thay đổi nó). + +#### Sử dụng + +Đính kèm giá trị `token` được trả về vào mỗi yêu cầu API bằng cách sử dụng header ` Authorization`: + + Authorization: Token YACub2KLfe8mfmHPcUKtt6t2SMJOGPXnZbqhc3nX + +### Bảo vệ CSRF + +Hầu hết các điểm cuối API `POST`/`PUT`/`DELETE` được bảo vệ chống lại [Giả mạo yêu cầu Cross-site](https://en.wikipedia.org/wiki/Cross-site_request_forgery). Điều này có nghĩa là không thể thực hiện các yêu cầu không trạng thái nếu không có xác thực. + +Khi sử dụng Khóa API hoặc Mã Token, bảo vệ CSRF bị bỏ qua. + +## Điểm cuối + +Phần tài liệu này vẫn đang được hoàn thiện. Chúng tôi đang nghiên cứu các tùy chọn để cung cấp tài liệu tự động về các điểm cuối. + +Mọi tiện ích mở rộng đều thêm các điểm cuối và thuộc tính mới, vì vậy rất khó để cung cấp tài liệu đầy đủ về tất cả các điểm cuối. Một cách tốt để phát hiện ra các điểm cuối là sử dụng các công cụ phát triển trình duyệt để kiểm tra các yêu cầu do ứng dụng một trang đưa ra. + +Dưới đây là một vài ví dụ về các điểm cuối thường được sử dụng. JSON đã được cắt bớt để giúp việc đọc dễ dàng hơn. + +### Danh sách cuộc thảo luận + + GET /api/discussions + +```json +{ + "links": { + "first": "https://flarum.tld/api/discussions", + "next": "https://flarum.tld/api/discussions?page%5Boffset%5D=20" + }, + "data": [ + { + "type": "discussions", + "id": "234", + "attributes": { + "title": "Lorem Ipsum", + "slug": "234-lorem-ipsum", + "commentCount": 10, + "participantCount": 3, + "createdAt": "2022-01-01T10:20:30+00:00", + "lastPostedAt": "2022-01-05T10:20:30+00:00", + "lastPostNumber": 10, + "canReply": true, + "canRename": true, + "canDelete": true, + "canHide": true, + "isHidden": true, + "hiddenAt": "2022-01-06T10:20:30+00:00", + "lastReadAt": "2022-01-02T10:20:30+00:00", + "lastReadPostNumber": 2, + "isApproved": true, + "canTag": true, + "isLocked": false, + "canLock": true, + "isSticky": false, + "canSticky": true, + "canMerge": true, + "subscription": null + }, + "relationships": { + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + "lastPostedUser": { + "data": { + "type": "users", + "id": "64" + } + }, + "tags": { + "data": [ + { + "type": "tags", + "id": "3" + } + ] + }, + "firstPost": { + "data": { + "type": "posts", + "id": "668" + } + } + } + }, + { + "type": "discussions", + "id": "234", + "attributes": { + // [...] + }, + "relationships": { + // [...] + } + }, + // [...] còn nhiều + ], + "included": [ + { + "type": "users", + "id": "1", + "attributes": { + "username": "Admin", + "displayName": "Admin", + "avatarUrl": null, + "slug": "1" + } + }, + { + "type": "users", + "id": "64", + "attributes": { + "username": "Flarum", + "displayName": "Flarum", + "avatarUrl": "https://flarum.tld/assets/avatars/Z4hEncw0ndVqZ8be.png", + "slug": "64" + } + }, + { + "type": "tags", + "id": "3", + "attributes": { + "name": "Welcome", + "description": "Post interesting things here", + "slug": "welcome", + "color": "#888", + "backgroundUrl": null, + "backgroundMode": null, + "icon": "fas fa-bullhorn", + "discussionCount": 30, + "position": 1, + "defaultSort": null, + "isChild": false, + "isHidden": false, + "lastPostedAt": "2022-01-05T10:20:30+00:00", + "canStartDiscussion": true, + "canAddToDiscussion": true, + "isRestricted": false + } + }, + { + "type": "posts", + "id": "668", + "attributes": { + "number": 1, + "createdAt": "2022-01-01T10:20:30+00:00", + "contentType": "comment", + "contentHtml": "

Hello World

" + } + }, + // [...] còn nhiều cuộc thảo luận khác + ] +} +``` + +### Tạo cuộc thảo luận + + POST /api/discussions + +```json +{ + "data":{ + "type": "discussions", + "attributes": { + "title": "Lorem Ipsum", + "content": "Hello World" + }, + "relationships": { + "tags": { + "data": [ + { + "type": "tags", + "id": "1" + } + ] + } + } + } +} +``` + +Phản hồi trả về bao gồm ID của cuộc thảo luận mới: + +```json +{ + "data": { + "type": "discussions", + "id": "42", + "attributes": { + "title": "Lorem Ipsum", + "slug": "42-lorem-ipsum", + "commentCount": 1 + // [...] other attributes + }, + "relationships": { + "posts": { + "data": [ + { + "type": "posts", + "id": "58" + } + ] + }, + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + // [...] các quan hệ khác + } + }, + "included":[ + { + "type": "posts", + "id": "38", + "attributes": { + "number": 1, + "contentType": "comment", + "contentHtml": "\u003Cp\u003EHello World\u003C\/p\u003E" + // [...] các thuộc tính khác + } + } + // [...] other includes + ] +} +``` + +### Tạo người dùng + + POST /api/users + +```json +{ + "data": { + "attributes": { + "username": "Flarum", + "email": "flarum@example.com", + "password": "correcthorsebatterystaple" + } + } +} +``` + +## Lỗi + +Flarum sử dụng nhiều mã trạng thái HTTP khác nhau và bao gồm các mô tả lỗi tuân theo [JSON:Thông số lỗi API](https://jsonapi.org/format/#errors). + +Dưới đây là một số lỗi phổ biến mà bạn có thể gặp phải khi sử dụng REST API: + +### Mã token CSRF không khớp + +Nếu bạn nhận được lỗi HTTP 400 với thông báo `csrf_token_mismatch`, điều đó có nghĩa là header `Authorization` không có hoặc không hợp lệ và Flarum đã cố gắng xác thực thông qua cookie phiên. + +```json +{ + "errors": [ + { + "status": "400", + "code": "csrf_token_mismatch" + } + ] +} +``` + +### Lỗi xác thực + +Lỗi xác thực được trả về với mã trạng thái 422 HTTP. Tên của trường không hợp lệ được trả về dưới dạng giá trị `pointer`. Có thể có nhiều lỗi cho một trường cùng một lúc. + +```json +{ + "errors": [ + { + "status": "422", + "code": "validation_error", + "detail": "The username has already been taken.", + "source":{ + "pointer":"\/data\/attributes\/username" + } + }, + { + "status": "422", + "code": "validation_error", + "detail": "The email has already been taken.", + "source": { + "pointer":"\/data\/attributes\/email" + } + } + ] +} +``` diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/scheduler.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/scheduler.md new file mode 100644 index 000000000..6123ce7c3 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/scheduler.md @@ -0,0 +1,55 @@ +# Scheduler + +The Flarum scheduler allows extensions to automate certain tasks effortlessly. In this guide we will see how to set it up. We won't go into the details of cron itself, but if you want to read more about it, I suggest you take a look at [this Wikipedia article](https://en.wikipedia.org/wiki/Cron) on cron. + +## Why should I care? + +Quite simply, a growing list of extensions now support handling certain functions automatically for you, completely behind the scenes. Wondering why `fof/drafts` 'scheduled drafts' are not posting, or `fof/best-answer` 'remind users to set a best answer after X days' does not fire? That'll be because they will setup themselves with the scheduler service, but without a one-liner cron job, nothing will happen! + +## What extensions currently use the scheduler? + +Some of the most popular examples are the following: + +- [FoF Best Answer](https://github.com/FriendsOfFlarum/best-answer) +- [FoF Drafts](https://github.com/FriendsOfFlarum/drafts) +- [FoF Sitemap](https://github.com/FriendsOfFlarum/sitemap) +- [FoF Open Collective](https://github.com/FriendsOfFlarum/open-collective) +- [FoF Github Sponsors](https://github.com/FriendsOfFlarum/github-sponsors) + +## Ok, let's get this setup! + +Most (if not all) Linux distros either come with, or can have, cron installed. For example, on Debian and Ubuntu based systems, you can install `cron` like this: + +``` +sudo apt-get update +sudo apt-get install cron +``` + +In case you are using a RHEL based Linux distribution (CentOS, AlmaLinux, Rocky Linux...), install cron like this: + +``` +sudo dnf update +sudo dnf install crontabs +``` + +Once you have cron installed, let's create the one and only entry you need for Flarum: + +``` +crontab -e +``` + +This will open the cron editor. You may or may not have other entries there. Add this line, and remember to leave an empty line at the bottom. + +``` +* * * * * cd /path-to-your-project && php flarum schedule:run >> /dev/null 2>&1 +``` + +`* * * * *` tells cron to run your command every minute. + +In case you want to use a different value and don't know exactly how cron expressions work, you can use a [cron expression generator](https://crontab.guru) to easily get the desired string. + +`cd /path-to-your-project && php flarum schedule:run` executes Flarum's scheduler to trigger any tasks currently waiting to be run. If PHP isn't in your system's path, you may need to experiment with setting the full path to PHP. + +Lastly `>> /dev/null 2>&1` suppresses any output from the command. + +Voila! Now any extension that registers a task to run, anything from every minute to daily, monthly, yearly - whatever - will now run on your server. diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/themes.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/themes.md new file mode 100644 index 000000000..66b38413b --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/themes.md @@ -0,0 +1,29 @@ +# Chủ đề + +Mặc dù chúng tôi đã làm việc chăm chỉ để làm cho Flarum đẹp nhất có thể, nhưng mỗi cộng đồng có thể sẽ muốn thực hiện một số chỉnh sửa/sửa đổi để phù hợp với phong cách mong muốn của họ. + +## Bảng điều khiển Quản trị + +The [admin dashboard](admin.md)'s Appearance page is a great first place to start customizing your forum. Tại đây, bạn có thể: + +- Chọn màu chủ đề +- Chuyển đổi chế độ tối và màu đầu trang +- Tải lên icon và favicon (icon hiển thị trong các tab của trình duyệt) +- Thêm HTML cho đầu trang và chân trang tùy chỉnh +- Thên [mã LESS/CSS](#css-theming) để thay đổi cách các phần tử được hiển thị + +## Chủ đề CSS + +CSS là một ngôn ngữ biểu định kiểu cho các trình duyệt biết cách hiển thị các phần tử của một trang web. Nó cho phép chúng tôi sửa đổi mọi thứ từ màu sắc, phông chữ đến kích thước phần tử và vị trí cho đến hình ảnh động. Thêm CSS tùy chỉnh có thể là một cách tuyệt vời để sửa đổi cài đặt Flarum của bạn cho phù hợp với chủ đề. + +Hướng dẫn CSS nằm ngoài phạm vi của tài liệu này, nhưng có rất nhiều tài nguyên trực tuyến tuyệt vời để tìm hiểu kiến ​​thức cơ bản về CSS. + +:::tip + +Flarum thực sự sử dụng LESS, giúp viết CSS dễ dàng hơn bằng cách cho phép các biến, điều kiện và hàm. + +::: + +## Tiện ích mở rộng + +[Hệ thống tiện ích mở rộng](extensions.md) linh hoạt của Flarum cho phép bạn thêm, xóa hoặc sửa đổi trên thực tế bất kỳ phần nào của Flarum. Nếu bạn muốn thực hiện các sửa đổi đáng kể về chủ đề ngoài việc thay đổi màu sắc/kích thước/kiểu dáng, thì một tiện ích mở rộng tùy chỉnh chắc chắn là cách tốt nhất. Để tìm hiểu cách tạo tiện ích mở rộng, hãy xem [tài liệu về tiện ích mở rộng](extend/README.md) của chúng tôi! diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md new file mode 100644 index 000000000..4014c6d98 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md @@ -0,0 +1,56 @@ +# Khắc phục sự cố + +Nếu Flarum không cài đặt hoặc hoạt động như mong đợi, điều đầu tiên bạn nên làm là *kiểm tra lại* xem môi trường của bạn có đáp ứng [yêu cầu hệ thống](install.md#server-requirements). Nếu bạn đang thiếu thứ gì đó mà Flarum cần để chạy, trước tiên bạn cần phải khắc phục điều đó. + +Tiếp theo, bạn nên dành vài phút để tìm kiếm trong [Diễn đàn hỗ trợ](https://discuss.flarum.org/t/support) và [trình theo dõi vấn đề](https://github.com/flarum/core/issues). Có thể ai đó đã báo cáo sự cố và bản sửa lỗi đã có sẵn hoặc đang được xử lý. Nếu bạn đã tìm kiếm kỹ lưỡng và không thể tìm thấy bất kỳ thông tin nào về vấn đề, đã đến lúc bắt đầu khắc phục sự cố. + +## Step 0: Activate debug mode + +:::danger Bỏ qua phần Sản xuất + +Các công cụ gỡ lỗi này rất hữu ích, nhưng có thể tiết lộ thông tin không nên công khai. Đây là những bước tốt nếu bạn đang sử dụng môi trường dàn dựng hoặc phát triển, nhưng nếu bạn không biết mình đang làm gì, hãy bỏ qua bước này khi ở trong môi trường sản xuất. + +::: + +Trước khi tiếp tục, bạn nên kích hoạt các công cụ gỡ lỗi của Flarum. Chỉ cần mở **config.php** bằng trình soạn thảo văn bản, thay đổi giá trị `debug` thành `true =` và lưu tệp. Điều này sẽ khiến Flarum hiển thị các thông báo lỗi chi tiết, giúp bạn có cái nhìn sâu sắc về những gì đang xảy ra. + +Nếu bạn thấy các trang trống và thay đổi ở trên không hữu ích, hãy thử đặt `display_errors` thành `On` trong tệp cấu hình **php.ini** của bạn. + +## Bước 1: Các lỗi phổ biến + +Rất nhiều vấn đề có thể được khắc phục bằng cách sau: + +* Xóa bộ nhớ cache của trình duyệt của bạn +* Xóa bộ đệm backend bằng [`php flarum cache:clear`](console.md). +* Đảm bảo rằng cơ sở dữ liệu của bạn được cập nhật với [`php flarum migrate`](console.md). +* Đảm bảo rằng [cấu hình email](mail.md) trong bảng điều khiển quản trị của bạn là đúng: cấu hình email không hợp lệ sẽ gây ra lỗi khi đăng ký, đặt lại mật khẩu, thay đổi email và gửi thông báo. +* Kiểm tra xem `config.php` của bạn có đúng không. Ví dụ: đảm bảo rằng `url` đang được sử dụng (`https` so với `http` và vấn đề phân biệt chữ hoa chữ thường ở đây!). +* Một thủ phạm tiềm năng có thể là đầu trang tùy chỉnh, chân trang tùy chỉnh hoặc LESS tùy chỉnh. Nếu sự cố của bạn nằm ở giao diện người dùng, hãy thử tạm thời xóa chúng qua trang Giao diện của trang tổng quan quản trị. + +Bạn cũng sẽ muốn xem kết quả đầu ra của [`php flarum info`](console.md) để đảm bảo rằng không có điều gì chính xảy ra. + +## Bước 2: Tạo lại vấn đề + +Cố gắng làm cho vấn đề xảy ra một lần nữa. Hãy chú ý cẩn thận đến những gì bạn đang làm khi nó xảy ra. Nó xảy ra mọi lúc, hay chỉ thỉnh thoảng? Hãy thử thay đổi một cài đặt mà bạn cho rằng có thể ảnh hưởng đến sự cố hoặc thứ tự mà bạn đang thực hiện. Nó có xảy ra trong một số điều kiện, nhưng không phải những điều kiện khác? + +Nếu gần đây bạn đã thêm hoặc cập nhật tiện ích mở rộng, bạn nên tạm thời vô hiệu hóa tiện ích đó để xem liệu điều đó có làm cho sự cố biến mất hay không. Đảm bảo rằng tất cả các tiện ích mở rộng của bạn đều được sử dụng với phiên bản Flarum bạn đang chạy. Các tiện ích mở rộng lỗi thời có thể gây ra nhiều vấn đề. + +Ở một nơi nào đó trong quá trình thực hiện, bạn có thể nhận ra ý tưởng về nguyên nhân gây ra sự cố của mình và tìm ra cách khắc phục nó. Nhưng ngay cả khi điều đó không xảy ra, bạn có thể sẽ tìm thấy một vài manh mối có giá trị giúp chúng tôi tìm ra điều gì đang xảy ra sau khi bạn đã gửi báo cáo lỗi của mình. + +## Bước 3: Thu thập thông tin + +Nếu có vẻ như bạn đang cần trợ giúp để giải quyết vấn đề, thì đã đến lúc nghiêm túc với việc thu thập dữ liệu. Tìm thông báo lỗi hoặc thông tin khác về sự cố ở những nơi sau: + +* Hiển thị trên trang thực tế +* Được hiển thị trong console của trình duyệt (Chrome: More tools -> Developer Tools -> Console) +* Được ghi lại trong nhật ký lỗi của máy chủ (ví dụ: `/var/log/nginx/error.log`) +* Được ghi lại trong nhật ký lỗi của PHP-FPM (ví dụ: `/var/log/php7.x-fpm.log`) +* Được ghi lại bởi Flarum (`storage/logs`) + +Sao chép bất kỳ tin nhắn nào vào tệp văn bản và ghi lại một vài ghi chú về *khi* xảy ra lỗi, bạn *bị gì* đang làm vào thời điểm đó. Đảm bảo bao gồm bất kỳ thông tin chi tiết nào bạn có thể thu thập được về các điều kiện mà sự cố xảy ra và không xảy ra. Thêm càng nhiều thông tin càng tốt về môi trường máy chủ của bạn: phiên bản hệ điều hành, phiên bản máy chủ web, phiên bản PHP và trình xử lý. + +## Bước 4: Chuẩn bị một báo cáo + +Khi bạn đã thu thập tất cả thông tin có thể về sự cố, bạn đã sẵn sàng để gửi báo cáo lỗi. Vui lòng làm theo hướng dẫn về [Báo cáo lỗi](bugs.md). + +Nếu bạn phát hiện ra điều gì đó mới về vấn đề này sau khi gửi báo cáo, vui lòng thêm thông tin đó vào cuối bài đăng ban đầu của bạn. Bạn nên gửi báo cáo ngay cả khi bạn đã tự mình giải quyết vấn đề, vì những người dùng khác cũng có thể được hưởng lợi từ giải pháp của bạn. Nếu bạn đã tìm thấy giải pháp tạm thời cho vấn đề, hãy nhớ đề cập đến vấn đề đó. \ No newline at end of file diff --git a/i18n/vi/docusaurus-plugin-content-docs/version-1.x/update.md b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/update.md new file mode 100644 index 000000000..9de400ff6 --- /dev/null +++ b/i18n/vi/docusaurus-plugin-content-docs/version-1.x/update.md @@ -0,0 +1,110 @@ +# Cập nhật + +## From the Admin Dashboard + +:::info + +If you have the extension manager extension installed you can simply run the update from its interface and skip this page entirely. + +::: + +--- + +Để cập nhật Flarum, bạn cần sử dụng [Composer](https://getcomposer.org). Nếu bạn không biết gì về nó, bạn cần phải biết 1 ít về Composer để cài đặt Flarum, đọc [hướng dẫn](composer.md) để biết cách cài đặt và sử dụng như thế nào. + +Nếu cập nhật trên các phiên bản chính (ví dụ: <= 0.1.0 đến 1.x.x, 1.x.x thành 2.x.x, ...), hãy nhớ đọc "hướng dẫn cập nhật phiên bản chính" thích hợp trước khi chạy các bước nâng cấp chung. + +## Các bước chung + +**Bước 1:** Đảm bảo các tiện ích mở rộng của bạn có phiên bản tương thích với phiên bản Flarum bạn đang cài đặt. Điều này chỉ cần thiết trên các phiên bản chính (ví dụ: bạn có thể không cần kiểm tra điều này nếu nâng cấp từ v1.0.0 lên v1.1.0, giả sử các tiện ích mở rộng của bạn tuân theo cách lập phiên bản được đề xuất). Bạn có thể kiểm tra điều này bằng cách xem [Cuộc thảo luận](https://discuss.flarum.org/t/extensions) của tiện ích mở rộng, tìm kiếm nó trên [Packagist](http://packagist.org/) hoặc kiểm tra cơ sở dữ liệu như [Extiverse](https://extiverse.com). Bạn sẽ cần phải xóa (không chỉ tắt) bất kỳ tiện ích mở rộng nào không tương thích trước khi cập nhật. Hãy kiên nhẫn với các nhà phát triển tiện ích mở rộng! + +**Bước 2:** Hãy xem tệp `composer.json` của bạn. Trừ khi bạn có lý do để yêu cầu các phiên bản tiện ích mở rộng hoặc thư viện cụ thể, bạn nên đặt chuỗi phiên bản của mọi thứ ngoại trừ `flarum/core ` thành `*` (bao gồm cả `flarum/tags`, `flarum/mentions` và các tiện ích mở rộng đi kèm khác). Đảm bảo rằng `flarum/core` KHÔNG được đặt thành `*`. Nếu bạn đang muốn cài phiên bản cụ thể của Flarum, hãy đặt `flarum/core` thành phiên bản đó (ví dụ: `"flarum/core":"v0.1.0-beta.16"`). Nếu bạn muốn phiên bản mới nhất, hãy sử dụng `"flarum/core":"^1.0"`. + +**Bước 3:** Nếu cài đặt cục bộ của bạn sử dụng [bộ mở rộng cục bộ](extenders.md), đảm bảo rằng chúng được cập nhật với những thay đổi trong Flarum. + +**Bước 4:** Chúng tôi khuyên bạn nên tắt tiện ích của bên thứ ba trong trang tổng quan quản trị trước khi cập nhật. Bước này không bắt buộc, nhưng sẽ giúp gỡ lỗi dễ dàng hơn nếu bạn gặp sự cố. + +**Bước 5:** Đảm bảo rằng phiên bản PHP của bạn được hỗ trợ bởi phiên bản Flarum mà bạn đang chuẩn bị nâgn cấp, và kiểm tra nó bằng cách sử dụng Composer 2 (`composer --version)`. + +**Bước 6:** Cuối cùng, chạy lệnh sau để cập nhật: + +``` +composer update --prefer-dist --no-plugins --no-dev -a --with-all-dependencies +php flarum migrate +php flarum cache:clear +``` + +**Bước 7:** Nếu có thể, hãy khởi động lại máy chủ PHP và opcache của bạn. + +## Hướng dẫn cập nhật phiên bản chính + +### Cập nhật từ Beta (<=0.1.0) lên Ổn định v1 (^1.0.0) + +1. Thực hiện các bước 1-5 ở trên. +2. Thay đổi chuỗi phiên bản của tất cả các tiện ích mở rộng đi kèm (`flarum/tags`, `flarum/mentions`, `flarum/likes`, vv) trong `composer.json` từ `^0.1.0` thành `*`. +3. Đổi phiên bản của `flarum/core` trong `composer.json` từ `^0.1.0` thành `^1.0`. +4. Xoá dòng `"minimum-stability": "beta",` từ tệp `composer.json` +5. Thực hiện bước 6 và 7 ở trên. + +## Các vấn đề gặp phải + +Có 2 nơi chính mà bạn có thể gặp lỗi khi cập nhật Flarum: khi đang chạy chính lệnh cập nhật hoặc khi truy cập diễn đàn sau khi cập nhật. + +### Gặp lỗi khi cập nhật + +Sau đây, chúng ta sẽ xem xét một số loại sự cố thường gặp khi cố gắng cập nhật Flarum. + +--- + +Nếu đầu ra ngắn và chứa: + +``` +Nothing to modify in lock file +``` + +Hoặc không liệt kê `flarum/core` như một gói cập nhật và bạn không sử dụng phiên bản flarum mới nhất: + +- Xem lại bước 2 ở trên, đảm bảo rằng tất cả các tiện ích mở rộng của bên thứ ba đều có dấu hoa thị cho chuỗi phiên bản của chúng. +- Đảm bảo yêu cầu phiên bản `flarum/core` của bạn không bị khóa đối với một phiên bản nhỏ cụ thể (ví dụ: `v0.1.0-beta.16` bị khóa, `^1.0.0` không). Nếu bạn đang cố gắng cập nhật các phiên bản chính của Flarum, hãy làm theo hướng dẫn cập nhật phiên bản chính có liên quan ở trên. + +--- + +Cho các lỗi khác, thử chạy `composer why-not flarum/core PHIÊN_BẢN_BẠN_MUỐN_NÂNG_CẤP_LÊN` + +Nếu đầu ra giống kiểu như này: + +``` +flarum/flarum - requires flarum/core (v0.1.0-beta.15) +fof/moderator-notes 0.4.4 requires flarum/core (>=0.1.0-beta.15 <0.1.0-beta.16) +jordanjay29/flarum-ext-summaries 0.3.2 requires flarum/core (>=0.1.0-beta.14 <0.1.0-beta.16) +flarum/core v0.1.0-beta.16 requires dflydev/fig-cookies (^3.0.0) +flarum/flarum - does not require dflydev/fig-cookies (but v2.0.3 is installed) +flarum/core v0.1.0-beta.16 requires franzl/whoops-middleware (^2.0.0) +flarum/flarum - does not require franzl/whoops-middleware (but 0.4.1 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/bus (^8.0) +flarum/flarum - does not require illuminate/bus (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/cache (^8.0) +flarum/flarum - does not require illuminate/cache (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/config (^8.0) +flarum/flarum - does not require illuminate/config (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/container (^8.0) +flarum/flarum - does not require illuminate/container (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/contracts (^8.0) +flarum/flarum - does not require illuminate/contracts (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/database (^8.0) +flarum/flarum - does not require illuminate/database (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/events (^8.0) +flarum/flarum - does not require illuminate/events (but v6.20.19 is installed) +... (this'll go on for a bit) +``` + +Rất có thể một số tiện ích mở rộng của bạn chưa được cập nhật lên phiên bản mới nhất. + +- Xem lại bước 1, đảm bảo rằng phiên bản của các tiện ích mở rộng của bạn tương thích với phiên bản core mà bạn đang cần cập nhật. Hãy xoá bất kỳ tiện ích nào không tương thích. +- Đảm bảo rằng bạn đang chạy `composer update` với tất cả các flag được chỉ định trong bước cập nhật. + +Nếu các cách khắc phục trên không giúp ích được cho bạn, hãy tham gia [Hỗ trợ diễn đàn](https://discuss.flarum.org/t/support). Khi đăng bài hỏi cách khắc phục, hãy kèm theo nội dung khi chạy lệnh `php flarum info` và `composer why-not flarum/core PHIÊN_BẢN_MÀ_BẠN_MUỐN_NÂNG_CẤP_LÊN`. + +### Gặp lỗi sau khi cập nhật + +Nếu bạn không thể truy cập diễn đàn của bạn sau khi cập nhật, làm theo [hướng dẫn khắc phục sự cố](troubleshoot.md). diff --git a/i18n/zh/docusaurus-plugin-content-docs/current.json b/i18n/zh/docusaurus-plugin-content-docs/current.json index f4ec6a00a..1e5f99cf2 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current.json +++ b/i18n/zh/docusaurus-plugin-content-docs/current.json @@ -1,6 +1,6 @@ { "version.label": { - "message": "下一节", + "message": "2.x", "description": "The label for version current" }, "sidebar.guideSidebar.category.Introduction": { @@ -39,4 +39,4 @@ "message": "内部文档", "description": "The label for category Internal Docs in sidebar internalSidebar" } -} \ No newline at end of file +} diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/README.md b/i18n/zh/docusaurus-plugin-content-docs/current/README.md index 0c5c7d96d..b98c1530a 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/README.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/README.md @@ -16,7 +16,7 @@ Flarum 的前身是 [esoTalk](https://github.com/esotalk/esoTalk) 和 [FluxBB](h * **漂亮、响应式。 ** 以人为本的论坛软件。 Flarum 被精心设计以在不同平台间保持一致性和直观性,开箱即用。 -* **强大、可扩展。** 您可以客制化、扩展或集成 Flarum 以满足您的社区需求。 Flarum 基于 [MIT 协议](https://github.com/flarum/flarum/blob/master/LICENSE) 发布。 +* **强大、可扩展。** 您可以客制化、扩展或集成 Flarum 以满足您的社区需求。 Flarum 基于 [MIT 协议](https://github.com/flarum/flarum/blob/master/LICENSE) 发布。 * **免费、开源。 ** Flarum 以 [MIT 许可证](https://github.com/flarum/flarum/blob/master/LICENSE) 发布。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/code-of-conduct.md b/i18n/zh/docusaurus-plugin-content-docs/current/code-of-conduct.md index 857eb2513..3b174f36b 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/code-of-conduct.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/code-of-conduct.md @@ -22,7 +22,7 @@ ### 提高自己的曝光度 -想发起一个新讨论? 请务必先阅读我们的 [常见问题](faq.md),通过其中的相关链接充分了解这个项目。 然后花一些时间浏览论坛,熟悉一下 [标签系统](https://discuss.flarum.org/tags),并搜索一些关键词,*可能您想讨论的早已被大家讨论过。

+想发起一个新讨论? 请务必先阅读我们的 [常见问题](faq.md),通过其中的相关链接充分了解这个项目。 然后花一些时间浏览论坛,熟悉一下 [标签系统](https://discuss.flarum.org/tags),并搜索一些关键词,*可能您想讨论的早已被大家讨论过。 当您确定要发起一个讨论时,请牢记: diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/README.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/README.md new file mode 100644 index 000000000..b98c1530a --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/README.md @@ -0,0 +1,45 @@ +- - - +slug: / +- - - + +# 关于 Flarum + +Flarum 是一款非常简洁的开源论坛软件。 它响应快速、简便易用,拥有打造一片成功的社区所需的所有功能。 它也极其可扩展,允许达到终极的可定制性。 + +![Flarum Home Screenshot](/en/img/home_screenshot.png) + +## 目标 + +Flarum 的前身是 [esoTalk](https://github.com/esotalk/esoTalk) 和 [FluxBB](https://fluxbb.org), 它生来就被设计如此: + +* **快速、简单。 ** 不杂乱不臃肿,没有复杂的依赖关系。 Flarum 使用 PHP 构建,因此很容易被部署。 界面采用高性能且小巧的 JavaScript 框架 [Mithril](https://mithril.js.org)。 + +* **漂亮、响应式。 ** 以人为本的论坛软件。 Flarum 被精心设计以在不同平台间保持一致性和直观性,开箱即用。 + +* **强大、可扩展。** 您可以客制化、扩展或集成 Flarum 以满足您的社区需求。 Flarum 基于 [MIT 协议](https://github.com/flarum/flarum/blob/master/LICENSE) 发布。 + +* **免费、开源。 ** Flarum 以 [MIT 许可证](https://github.com/flarum/flarum/blob/master/LICENSE) 发布。 + +你可以在这里阅读更多关于我们 [对于 Flarum 的哲学和价值观](https://discuss.flarum.org/d/28869-flarum-philosophy-and-values) 的信息。 + +## 帮助Flarum项目 + +Flarum 是 [免费、开源](https://github.com/flarum/core) 的软件,由志愿者们维护和管理。 我们依靠社区的贡献来帮助我们改进和拓展 Flarum。 + +🧑‍💻 如果你是一个开发者,可以考虑 [为Flarum或者其扩展做出贡献](contributing.md)。 这是帮助 Flarum 的**最有效的方式**,而且您的帮助可能会产生很大的影响:市面上有成千上万的Flarum站点,拥有数百万的最终用户。 + +🧩 如果有您缺少的功能,或您有一些新的想法,[编写一个自定义扩展](extend/README.md) 将使 Flarum 更适合您和其他人使用。 + +✒️ 如果您在技术写作方面有经验,那么您对[我们文档](https://github.com/flarum/docs/issues)的贡献将有助于未来的用户、管理员和开发人员充分利用 Flarum。 + +🌐 如果您会说多种语言,那么您可以 [为Flarum提供翻译](extend/language-packs.md),从而帮助世界各地无数用户访问 Flarum。 + +💸 Flarum基金会 并不通过Flarum赚钱,但确实有账单要付。 首先,非常感谢您有捐款意向,您可以在 [Github Sponsors](https://github.com/sponsors/flarum) 或 [OpenCollective](https://opencollective.com/flarum) 上捐款。 在过去,我们还能够在财务上支持一些核心开发人员,这样他们就可以兼职工作于 Flarum。 如果没有您的财政支持,这是不可能的。 + +🧑‍🤝‍🧑 加入 [我们的社区](https://discuss.flarum.org) 来讨论 Flarum 的发展,获得实例帮助,或者遇见一些很酷的人! 如果您熟悉 Flarum,您还可以帮助初学者! + +🐛 如果有 bug 困扰着您,或者您脑海中有一个功能的想法,在您告诉我们之前我们是不会知道的! 我们通过 [GitHub issues](https://github.com/flarum/core/issues) 跟踪错误、建议和未来的开发计划。 如果已经有 issue 被打开,点个赞和添加一些(建设性的)额外信息可能对我们非常有帮助! + +📣 如果您喜欢 Flarum ,请考虑在博客/推特/聊天中提到它! 更多的人认识到 Flarum,就会有更多的人参与 Flarum,从而带来更多的活动、更好的扩展和更快的发展。 + +没有我们社区的贡献,Flarum就不会有今天。 如果您有意贡献,请参阅我们的 [开发人员贡献](contributing.md) 和 [其他贡献](contributing-docs-translations.md) 文档以获取更多信息。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/admin.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/admin.md new file mode 100644 index 000000000..74a41cdbc --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/admin.md @@ -0,0 +1,13 @@ +# 后台管理面板 + +Flarum 管理面板是一个友好的论坛管理界面。 且只对「管理组」成员可见。 点击论坛右上角您的 **用户名**, 选择 **后台管理** 即可进入管理面板。 + +管理员控制面板有如下部分,具体是: +- **仪表盘** - 显示主要的管理员控制面板,包含统计信息和其他相关信息。 +- [常规](https://docs.flarum.org/mail) - 设置论坛名称、简介以及其他基础设置。 +- **邮箱** - 允许您配置论坛邮件服务。 更多信息请 [点击此处](https://docs.flarum.org/mail)。 +- **权限** - 显示每个用户组的权限,并允许您配置全站和特定范围。 +- **外观** - 允许您自定义论坛的颜色、图标和添加额外的 CSS 以自定义论坛样式。 +- **用户** - 为您提供论坛中所有用户的分页列表,可以在此编辑或管理用户。 + +除了以上提到的这些部分,主管理面板还通过_扩展_部分来允许你管理安装的扩展,这也包括 Flarum 的核心扩展,例如 Tags。 在 _主题 _ 和 _语言_ 模块下,您可以修改论坛主题或使用扩展以适应多语言。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/appearance.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/appearance.md new file mode 100644 index 000000000..6b4c5452f --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/appearance.md @@ -0,0 +1,3 @@ +# 外观 +此页面正在建设中。 +This page is under construction. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/bugs.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/bugs.md new file mode 100644 index 000000000..49366fae4 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/bugs.md @@ -0,0 +1,28 @@ +# 反馈 Bug + +:::danger 安全漏洞 + +如果您发现 Flarum 存在安全漏洞,请遵循我们的[安全政策](https://github.com/flarum/core/security/policy),我们会及时处理 + +::: + +感谢您帮助我们测试 Flarum! 我们很高兴让您加入这个队伍! 我们需要可以*排除问题*和*清晰地沟通*的人。 您可能知道,优秀的错误报告需要花费一些时间和精力。 如果您可以做到这些,那让我们开始吧! + +## 重复项 + +已经发现了 Bug? 太棒了! 我们很乐意听到关于它的消息— 但首先您应该检查一下相关情况,以确保您不会在一个已知问题上浪费时间: + +- 搜索我们的 [支持论坛](https://discuss.flarum.org/t/support) 来查看它是否已经报告。 +- 我们也可能正在进行修复,所以也请搜索我们的 [问题跟踪器](https://github.com/flarum/core/issues)。 + +在 *彻底地*搜索一番后,如果无人报告该问题,欢迎您提交报告。 如果只是一个简单的小问题(例如单词拼写问题或图像问题),请直接跳到下一节。 但如果您看到错误,或者它已经明显损坏,我们需要您先收集一些信息。 请跳转到我们的 [故障排除](troubleshoot.md) 指南并遵循那里的指引。 请收集尽可能多的信息! + +## 报告 + +我们在GitHub上跟踪问题。 请您确保在 [正确的仓库](https://github.com/flarum) 创建问题(Issue),并填写模版中的所有内容。 + +如果可以,请检查最新版本的 Flarum 是否可以重现该问题。 如果您使用的是预发布版本或开发版本,请指出您正在使用的版本。 + +记住:错误报告的目的是让我们轻松地重现并修复它。 您可能需要阅读 [这篇文章](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html),了解如何撰写有效的错误报告。 请您 **务必** 清晰描述重现问题的必要步骤。 没有明确重现步骤的问题将不会被标记/分类。 如果一个标记为「需要验证(needs verification)」的问题从被标记开始 5 天内创建者没有进一步反馈信息,该问题将被关闭。 + +一旦您提交了报告,请您 *持续关注* 并耐心等待。 我们可能需要要求进一步的细节或说明。 但我们总是有很多事情要做,所以我们可能需要一段时间才会处理您的报告。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md new file mode 100644 index 000000000..3b174f36b --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/code-of-conduct.md @@ -0,0 +1,51 @@ +# 行为准则 + +### _欢迎光临 Flarum 社区!_ + +... 感谢您的加入! 我们对 Flarum 充满信心与激情,也很高兴认识同样的人。 我们希望 *每个人* 都能从 Flarum 及其社区中得到最大的帮助,因此请阅读并遵守下列准则。 我们希望每位用户都能充分利用 Flarum 和 Flarum 社区,因此,请您阅读并遵守以下准则。 无论您是使用我们的论坛,还是在 Discord、GitHub 上交流,亦或是在其他平台进行任何形式的交流,这些准则均适用。 + +### 重中之重,为人友善! + +我们在这里探讨与 Flarum 有关的事情,并努力使她成长为一个更完美的程序。 批判思维(当然,得通过合理的论证)是其中重要的一环。 不过千万不要冲动,不要让事态演变成人身攻击,不要让消极情绪搞人心态。 因此,请杜绝以下行为: + +- 发表攻击性或辱骂性的、以及任何形式的仇恨词汇或言论; +- 发表旨在骚扰、冒充或诽谤他人的帖子; +- 毫无必要地删除已发布的帖子; +- 未经自然人同意,滥用或企图滥用、公开或企图公开他人的个人信息; +- 发表淫秽或色情内容(包括但不限于文字、链接或图片等); +- 发表垃圾信息、钓鱼贴,以及任何旨在破坏本网站的行为; +- 讨论盗版软件或类似事情。 + +*上述条例将作为版主采取行动的依据。 * 如果您对其他成员有意见,请不要相互对峙。 如果违规行为发生于论坛,请 *举报* 相关帖字,然后等待工作人员处理。 否则,请通过我们的 [联系页面](https://flarum.org/foundation/contact) 报告不合法的违规行为。 + +我们的管理员和版主可以编辑或删除任何具有冒犯性或破坏性的内容。 严重或屡次违规的用户,可能会被封禁账户。 所以,你懂的,*待人友善一些*。 😎 + +### 提高自己的曝光度 + +想发起一个新讨论? 请务必先阅读我们的 [常见问题](faq.md),通过其中的相关链接充分了解这个项目。 然后花一些时间浏览论坛,熟悉一下 [标签系统](https://discuss.flarum.org/tags),并搜索一些关键词,*可能您想讨论的早已被大家讨论过。 + +当您确定要发起一个讨论时,请牢记: + +- 起个好标题! 如果您的标题能简洁明了地阐明您要讨论的内容,您会得到更加理想的结果。 +- 标签要选对! 这将增加帖子被及时阅读、回复的可能性。 +- *不要*翻来覆去的发布相同主题的帖子。这样通常会适得其反。 +- 如果不使用标签组标记为多语言,则请*务必使用英语来发表帖子*。如果我们无法理解你发的帖子想表达什么,我们就无从帮助你。 +- 不要在帖子中签名或者添加小尾巴! 个人资料的辨识度足够了。 + +帮我们一起把事务整理的有条不紊吧。 可别让我们把用来了解您、帮助您解决问题、谈论 Flarum 的大好时光浪费在杂七杂八的琐碎事儿上,您说对吗? 毕竟,那才是我们应该在这里做的事情。 + +### 提升您回帖的价值 + +大家参与讨论,都是希望自己的观点或建议能被他人采纳、为他人提供帮助。 既然如此,为什么不从一开始就让您的回帖值得一读呢? + +- 不要回复标题。 花点时间 *看一下* 看看一楼在说什么,至少先 *速览一下* 后面的对话。 +- 问问自己,您的回复是否对讨论有帮助。 如果没有,请斟酌斟酌。 +- 避免仅仅为了同意某人就去顶帖,您可以使用「喜欢」按钮表达您的态度。 +- 不要刷帖。 这里是论坛,不是聊天室。 +- 如果您的回复偏题了,或者会导致整个讨论的方向发生转变,请考虑发起一个全新的讨论。 +- 如果您只是想发表一些废话,作为测试,请到[「测试」](https://discuss.flarum.org/t/sandbox)标签中发表。 +- 请确保您的回复能提供建设性的反馈和支持,以便建设一个惠及所有人的社区。 + +没有人会抱怨一次两次的笑话或者是抖机灵的评论。 我们喜欢快保持着轻松的气氛! 不过为了保证办事效率,请不要和讨论完全脱轨。 + +> 感谢 Dominion 帮助我们制定了这些准则。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/composer.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/composer.md new file mode 100644 index 000000000..6a4bbcb38 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/composer.md @@ -0,0 +1,152 @@ + +# Composer + +Flarum 使用一个叫 [Composer](https://getcomposer.org) 的程序来管理其依赖包和扩展程序。 你需要 Composer 以实现: + +- 通过命令行安装或更新 Flarum +- 通过命令行安装、更新或删除 Flarum 扩展 + +本指南会简单阐述 Composer 的使用。 我们强烈建议查阅 [官方文档](https://getcomposer.org/doc/00-intro.md) 以获取更多信息。 + +:::tip 即刻测试 Flarum? + +在共享主机上,建议使用扩展管理器扩展而不是 Composer。 这是一个 Composer 的图形界面,允许您安装、更新和删除扩展,而无需使用 SSH。 您可以直接用一个归档安装 Flarum,而不需要 Composer。 在扩展管理器预装后,请检查[安装指南](install.md#installing-by-unpacking-an-archive)获取更多信息。 + +::: + +## 什么是 Composer? + +> Composer 是一个 PHP 依赖管理工具。 它允许您声明项目所依赖的库,并管理 (安装/更新) 这些库 。 — [Composer Introduction](https://getcomposer.org/doc/00-intro.md](https://getcomposer.org/doc/00-intro.md)) + +每次安装 Flarum 都包含了 Flarum 的核心和一系列的 [扩展](extensions.md) 他们都有自己的自己的依赖和发布包。 + +在过去,论坛框架会通过让用户上传带有拓展代码的压缩文件来管理拓展。 这看上去很简单,但问题会很快显现出来: + +- 通过网络上传随机的压缩文件通常是一个不好的主意。 要求扩展从像 [Packagist](https://packagist.org/) 这样的中央源头下载能够使得恶意代码的传播变得更加繁琐,并确保源代码在 GitHub 上对免费/公共扩展可用。 +- 比方说,扩展 A 需要某个库的第 4 版,而扩展 B 需要同一个库的第 5 版。 在基于压缩文件的解决方案中,这两个依赖中的任何一个都可能覆盖另一个,以造成各种不一致的问题。 或者两个都试图同时运行,这将导致 PHP 崩溃(同一个类不能声明两次)。 +- 如果试图自动部署,运行自动测试,或扩展到多个服务器节点,压缩文件会造成很多麻烦。 +- 我们无法确保冲突的扩展版本不被安装,或者确保系统的 PHP 版本和扩展要求被满足。 +- 当然,我们可以通过替换压缩文件来升级扩展。 但是,升级 Flarum 核心呢? 我们又如何确保扩展可以声明它们与哪些版本的核心兼容? + +Composer 解决了所有这些,乃至更多的问题! + +## Flarum & Composer + +当你去 [安装 Flarum](install.md#installing) 时,你实际上在做两件事。 + +1. 下载一个 Flarum 的模板“骨架”。 这包括一个处理网络请求的 `index.php` 文件,一个提供 CLI 的 `flarum` 文件,以及一系列的网络服务器配置和文件夹设置。 这是从[`flarum/flarum` github仓库](https://github.com/flarum/flarum)中提取的,实际上并不包含 Flarum 运行所需的任何代码。 +2. 安装 Flarum 所需的 `composer` 包,即 Flarum 核心和几个捆绑的扩展。 这些是由步骤 1 中的 `index.php` 和 `flarum` 文件调用的,是 Flarum 的实现。 这些都是在骨架中的 `composer.json` 文件中指定的。 + +当你想更新 Flarum 或添加/更新/删除扩展时,你将通过运行 `composer` 命令来实现。 每个命令都不同,但所有命令都遵循相同的一般流程: + +1. 更新 `composer.json` 文件来添加/删除/更新软件包。 +2. 如果可能的话,我们需要做一些计算以得知所有依赖的最新兼容版本,或者弄清楚为什么所要求的安排是不可能的。 +3. 如果一切正常,下载所有需要更新的东西的新版本。 如果遇到问题,你可以尝试恢复 `composer.json` 的更改。 + +当运行 `composer.json` 命令时,一定要注意输出信息。 如果有错误,它可能会告诉你是否是因为扩展程序不兼容,不支持的 PHP 版本,缺少 PHP 扩展程序,或其他原因。 + +### `composer.json` 文件 + +如上所述,整个 Flarum 网站的 composer 配置都包含在 `composer.json` 文件中。 你可以查阅 [composer 文档](https://getcomposer.org/doc/04-schema.md)以了解具体的模式,但现在,让我们看看来自 `flarum/flarum` 的 `composer.json` 注释: + +```json +{ + // 以下章节大部分只是关于包的元数据。 + // 对论坛管理员来说,这并不重要。 + "name": "flarum/flarum", + "description": "Delightfully simple forum software.", + "type": "project", + "keywords": [ + "forum", + "discussion" + ], + "homepage": "https://flarum.org/", + "license": "MIT", + "authors": [ + { + "name": "Flarum", + "email": "info@flarum.org", + "homepage": "https://flarum.org/team" + } + ], + "support": { + "issues": "https://github.com/flarum/core/issues", + "source": "https://github.com/flarum/flarum", + "docs": "https://flarum.org/docs/" + }, + // 元数据结束 + + // 下面是我们最关心的部分 + // 这是我们想要的包清单和每个包的版本。 + // 我们会简单略过他们 + "require": { + "flarum/core": "^1.0", + "flarum/approval": "*", + "flarum/bbcode": "*", + "flarum/emoji": "*", + "flarum/lang-english": "*", + "flarum/flags": "*", + "flarum/likes": "*", + "flarum/lock": "*", + "flarum/markdown": "*", + "flarum/mentions": "*", + "flarum/nicknames": "*", + "flarum/pusher": "*", + "flarum/statistics": "*", + "flarum/sticky": "*", + "flarum/subscriptions": "*", + "flarum/suspend": "*", + "flarum/tags": "*" + }, + + // Composer 的配置多种多样。 这是合理的默认值。 + // 您可在 https://getcomposer.org/doc/06-config.md 找到选项列表。 + "config": { + "preferred-install": "dist", + "sort-packages": true + }, + + // 如果 composer 可以找到一个软件包的稳定(而非测试)版本, + // 它应当使用它。 一般来说,生产站点不应运行测试版软件, + // 除非你明白自己在做什么。 + "prefer-stable": true +} +``` + +让我们把重点放在 `require` 部分。 这个部分的每个条目都是一个 composer 包的名字和一个版本字符串。 要阅读更多关于版本字符串的信息,请参见相关的 [composer documentation](https://semver.org/)。 + +对于 Flarum 项目来说,在安装 `flarum/core` 的 `require` 字段中,你会看到有几种类型的条目: + +- 你必须有一个 `flarum/core` 节点。 这应该包含一个与您想要安装的版本相对应的明确的版本字段。 对于 1.x 版本的 Flarum,这应是 `^1.0`。 +- 你应该为你安装的每个扩展配备一个节点。 一些内置扩展(比如 `flarum/tags` 和 `flarum/suspend` 等)已被默认包含,[其他的由您通过 composer 指令添加](extensions.md)。 除非你有其它原因(比如正在测试一个包的测试版本),我们建议使用星号作为扩展的版本字段(`*`)。 它的意思是“安装与我的 flarum/core 相适配的最新版本”。 +- 某些扩展/功能可能需要 PHP 包,而不是 Flarum 扩展。 比如,你需要 guzzle 库来使用 [Mailgun 邮件驱动器](mail.md)。 在这种情况下,该扩展/功能的说明应该解释使用哪个版本字段。 + +## 如何安装 Composer? + +就像其他的软件一样,Composer需要先安装在你要安装Flarum的服务器上 这里有很多选项,取决于你使用网站服务的类型 + +### 独立服务器 + +在这种情况下,你可以安装Composer通过阅读[Composer Guide](https://getcomposer.org/doc/00-intro.md#system-requirements) + +### 共享服务器 + +如果Composer没有预先安装(你可以通过执行`composer --version`命令来判断),你可以查阅[手动安装手册](https://getcomposer.org/composer-stable.phar) 只需要上传 composer.phar 到你的文件夹中,并执行`/path/to/your/php7 composer.phar COMMAND` 对于所有的命令应该以`composer COMMAND`执行 + +:::danger + +互联网上的一些文章会提到你可以使用像 PHP shell 这样的工具。 如果你不知道你在做什么或他们在说什么,请小心! 无保护的 web shell 是 **极危险的**。 + +::: + +## 如何使用 Composer + +你需要在命令行界面(CLI)上运行 Composer。 请确保你可以通过 SSH 访问你的服务器。 + +一旦你安装了 Composer,你应该能够通过 `composer COMMAND` 在您的 SSH 终端中运行 composer 命令。 + +:::info 优化 + +在大多数命令后,你可以运行 `composer dump-autoload -a`。 基本上,这会缓存 PHP 文件使他们运行得更快。 + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/config.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/config.md new file mode 100644 index 000000000..e0331c835 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/config.md @@ -0,0 +1,35 @@ +# 配置文件 + +除数据库外,只有一处配置是无法通过后台管理面板修改的,那就是位于 Flarum 安装根目录下的 `config.php` 文件。 + +虽然这个文件很小,但包含了 Flarum 安装时至关重要的信息。 + +如果存在这个文件,Flarum 就知道它自己已经被安装了。 另外这个文件还为 Flarum 提供数据库信息等内容。 + +下面是一个示例文件,我们来了解一下所有内容的含义: + +```php + false, // 启用或禁用调试模式,用于排查问题 + 'offline' => false, // 启用或禁用网站维护模式。这使得所有用户(包括管理员)无法访问您的网站。 + 'database' => + array ( + 'driver' => 'mysql', // 数据库驱动,例如 MySQL, MariaDB …… + 'host' => 'localhost', // 连接的主机,除非使用外部服务,否则多数情况下是 localhost + 'database' => 'flarum', // 数据库实例名 + 'username' => 'root', // 数据库用户名 + 'password' => '', // 数据库密码 + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', // 数据表的前缀,如果您和其他服务共享一个数据库,那么添加前缀会很有用 + 'port' => '3306', // 连接数据库的端口,MySQL 默认为 3306 + 'strict' => false, + ), + 'url' => 'https://flarum.localhost', // URL 配置,如果您改变了域名,您需要变更这个 + 'paths' => + array ( + 'api' => 'api', // /api 跳转到 API + 'admin' => 'admin', // /admin 跳转到 admin + ), +); +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/console.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/console.md new file mode 100644 index 000000000..3cbf42389 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/console.md @@ -0,0 +1,77 @@ +# 控制台 + +除了 Flarum 核心提供的 [默认命令](../console.md),我们还允许扩展程序的开发者添加自定义控制台命令。 + +使用控制台: + +1. `ssh` 连接到安装 Flarum 的服务器 +2. `cd` 进入含有一个叫做 `flarum` 的文件的文件夹中 +3. 执行 `php flarum [命令名]` + +## 注册控制台命令 + +### list + +要注册控制台命令,请在您插件的 `extend.php` 文件中使用 `Flarum\Extend\Console` 扩展器: + +### help + +`php flarum help [命令名]` + +输出指定命令的帮助信息。 + +要以其他格式输出,请添加 --format 参数: + +`php flarum help --format=xml list` + +要显示可用的命令列表,请使用 list 命令。 + +### info + +`php flarum info` + +获取 Flarum 核心及已安装插件的信息。 调试问题时这个命令会很有用,在您提交的问题报告中也应当附上该输出内容。 + +### cache:clear + +`php flarum cache:clear` + +清楚后端 Flarum 缓存,包括已生成的 js/css,文本格式器缓存、翻译缓存。 这应当在每次安装或移除扩展后运行,在出现问题时这应该是第一步。 + +### assets:publish + +`php flarum migrate:reset --extension [插件ID]` + +发布核心和扩展插件中的资源文件(例如编译的 JS/CSS、bootstrap 图标、logos 等)。 这在您的资源文件发生损坏,或者您切换了 [文件系统驱动程序](extend/filesystem.md) 的 `flarum-assets` 存储磁盘时可以帮助您。 + +### 迁移 + +`php flarum migrate` + +执行所有未完成的迁移。 当安装或更新一个要修改数据库的插件时,会用到此命令。 + +### migrate:reset + +`php flarum migrate:reset --extension [插件ID]` + +重置指定插件的所有迁移。 这个命令大多被插件开发人员使用,如果您要卸载插件,并且想要从数据库中清除该插件的所有数据,也会需要用它。 请注意,该命令的被执行插件必须处于已安装状态(插件启用不启用都行)。 + +### schedule:run + +`php flarum schedule:run` + +许多扩展使用预定作业定期执行任务。 包括清理数据库缓存,定时发布草稿,生成站点地图等。 If any of your extensions use scheduled jobs, you should add a [cron job](https://ostechnix.com/a-beginners-guide-to-cron-jobs/) to run this command on a regular interval: + +``` +* * * * * cd /path-to-your-flarum-install && php flarum schedule:run >> /dev/null 2>&1 +``` + +这个命令一般不应被手动执行。 + +Note that some hosts do not allow you to edit cron configuration directly. In this case, you should consult your host for more information on how to schedule cron jobs. + +### schedule:list + +`php flarum schedule:list` + +此命令将返回已计划命令的列表(更多信息请参阅 `schedule:run`)。 这有助于确认扩展程序提供的命令已正确注册。 This **can not** check that cron jobs have been scheduled successfully, or are being run. \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md new file mode 100644 index 000000000..4d4c78a3a --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/contributing-docs-translations.md @@ -0,0 +1,26 @@ +# 文档与翻译 + +## 补充文档 + +补充文档可以帮助无数未来的Flarum用户。 你可以在以下几点上下功夫: + +- 帮助Flarum最终用户使用一些高级Flarum功能的用户指南。 +- 更多 [常见问题](faq.md)。 +- 更加详细的 [故障排除](troubleshoot.md) 的步骤。 +- Flarum 开发或安装的逐步教程。 +- 扩展开发者的[技术参考指南](extend/README.md)。 +- 帮助我们提升你认为我们应该进一步阐述或更好地解释的其他事物。 + +找到相关主题的好方法是在我们社区的 [支持标签](https://discuss.flarum.org/t/support) 中寻找常见问题。 + +## 翻译Flarum + +我们希望每个人都能使用Flarum,不论其掌握的语言种类! 通过提供翻译,您可以让更多的人享受Flarum。 最好的是,我们使用方便用户的用户界面进行翻译,所以如果您想提供帮助,不需要硬性技术要求! + +Flarum Core的翻译、捆绑扩展和社区扩展是通过 [Weblate](https://weblate.rob006.net/projects/flarum/) 管理的。 + +此文档的翻译通过 [Crowdin](https://crowdin.com/project/flarum-docs) 管理。 + +Flarum基金会设立了“flarum-lang”组织,以支助笔译员以确保各种语言包的可用性。 您可以通过 [访问 GitHub 仓库](https://github.com/flarum-lang/about) 了解更多信息。 + +如果你想要支持现有的语言包,开始一项新的翻译,或者在使用weblate或crowdin时出现问题,您 [最好与 `flarum-lang` 团队](https://discuss.flarum.org/d/27519-the-flarum-language-project) 取得联系。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/contributing.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/contributing.md new file mode 100644 index 000000000..db188b72f --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/contributing.md @@ -0,0 +1,170 @@ +# 贡献代码 + +有兴趣为 Flarum 的发展做贡献吗? 那太好了! 竭诚欢迎,[报告错误](bugs.md) 或是 Pull Request 都没问题! 没有我们社区的贡献,Flarum就不会有今天。 + +在贡献之前,请仔细阅读 [行为准则](code-of-conduct.md)。 + +本文档是想要为 Flarum 贡献代码的开发者的指南。 如果您只是入门,建议您阅读进阶文档中的 [Getting Started](https://flarum.org/extend/start.md) 文档了解 Flarum 的工作原理。 + +## 为什么要为Flarum做贡献? + +⚡ **作出实际影响。** 成千上万的Flarum实例,和数百万的累积最终用户, 都会因为你的贡献而受益。 + +🔮 **塑造Flarum的未来。** 我们有很长的待办事项列表,但时间有限。 如果你愿意成为一个特性或更新的代言人,它将更有可能发生,并且你将能够实现你的愿景。 此外,我们的路线图和里程碑是由我们 [的核心开发团队](https://flarum.org/team)设定的,我们所有人都是贡献者。 影响的最佳途径是贡献。 + +🧑‍💻 **成为更好的工程师。** 我们的代码库是现代化的,我们非常重视良好的工程和清晰的代码。 在设计、基础设施、性能和可扩展性方面,也有很多有趣、具有挑战性的问题需要解决。 特别的,如果你是一名学生或处于职业生涯的初期,参与 Flarum 的开发是一个培养开发技能的绝佳机会。 + +🎠 **很有趣!** 我们非常喜欢在 Flarum 上工作:有很多有趣的挑战和有趣的特性可以构建。 我们在[论坛](https://discuss.flarum.org)和 [Discord 服务器](https://flarum.org/chat)上也有一个活跃的社区。 + +## 开发设置 + +请查看我们的规划 [里程碑](https://github.com/flarum/core/milestones),了解一下需要做的事情。 您可以查看[「Good first issue」](https://github.com/flarum/core/labels/Good%20first%20issue)标签中的 Issue,这些 Issue 都比较容易上手。 有任何您不确定的问题,不要犹豫,直接提问! 我们曾经都是新手。 + +如果您打算揽下某项工作,请先在相关 Issue 上发表评论或创建一个新的 Issue 告知我们, 以免做无用功。 + +由于 Flarum 是如此依赖扩展,因此在处理核心问题以及捆绑扩展时,我们强烈推荐使用[我们的扩展文档](extend/README.md)作为参考。 你应该从[介绍](extend/README.md)开始,以更好地了解我们扩展中的学问。 + +## 开发流程 + +### 建立本地代码库 + +[flarum/flarum 是一个「骨架」应用程序,它使用 Composer 下载核心包 和 一堆扩展程序](https://github.com/flarum/flarum)。 Flarum 核心、扩展和前述使用的所有包的源代码都位于 Flarum Monorepo [flarum/framework ](https://github.com/flarum/framework)中。 若要对其进行贡献,你需要在本地 fork 和 clone Monorepo 代码库,然后将其作为 [Composer 路径库](https://getcomposer.org/doc/05-repositories.md#path)添加到开发环境中: + +```bash +git clone https://github.com/flarum/flarum.git +cd flarum + +# 或者,如果你想要直接克隆到当前目录: +git clone https://github.com/flarum/flarum.git . +# Note, the directory must be empty + +# Set up a Composer path repository for Flarum monorepo packages +composer config repositories.0 path "PATH_TO_MONOREPO/*/*" +git clone https://github.com//framework.git PATH_TO_MONOREPO +``` + +一个典型的贡献流程如下所示: + +最后,运行 `composer install` 从本地路径存储库完成插件安装。 + +准备好以上本地环境后,请务必打开 **config.php** 中的 `debug` 调试模式,并在 PHP 配置中将 `display_errors` 设置为 `On`。 这样您就能同时看到 Flarum 和 PHP 的详细报错内容。 调试模式还会在每个请求时强制重新编译Flarum的文件,省去了在每次更改扩展的JavaScript或CSS后调用`php flarum cache:clear`的需要。 + +Flarum 的前端代码是用 ES6 编写的,并已编译为 JavaScript。 在开发过程中,你需要使用 [Node.js ](https://nodejs.org/)和 [`yarn`](https://yarnpkg.com/) 重新编译 JavaScript。 **请不要在发送 PR 时提交生成的 `dist `文件**;这会在更改合并到`主分支`时自动处理。 + +要为前端做出贡献,你需要先安装 JavaScript 依赖项。 Monorepo 使用[ yarn 工作区](https://classic.yarnpkg.com/lang/en/docs/workspaces/)来轻松地在所有包之间安装 JS 依赖项。 + +```bash +cd packages/framework +yarn install +``` + +Then you can watch JavaScript files for changes during development: + +```bash +cd framework/core/js +yarn dev +``` + +对于扩展程序,过程是一样的。 + +```bash +cd extensions/tags/js +yarn dev +``` + +### 开发工具 + +在 fork 和 clone 要工作的代码库之后,你需要设置本地主机来测试你的更改。 Flarum 目前没有开发服务器,所以你需要设置 Apache/NGINX/Caddy 等来提供本地 Flarum 安装的服务。 + +或者,你可以使用以下工具:[ Laravel Valet](https://laravel.com/docs/master/valet)(Mac)、[XAMPP](https://www.apachefriends.org/index.html)(Windows)或 [Docker-Flarum](https://github.com/mondediefr/docker-flarum)(Linux)来提供本地论坛服务。 + +大多数 Flarum 贡献者使用 [PHPStorm](https://www.jetbrains.com/phpstorm/download/) 或 [Visual Studio Code](https://code.visualstudio.com/) 进行开发。 + +## 编码风格 + +典型的作出贡献的工作流会像这样: + +0. 🧭 **计划** 为你的贡献做计划。 + * *Bug 修复* 应当提交合并到最新的稳定分支。 + * 与当前 Flarum 版本完全向后兼容的 *次要* 功能可以提交合并到最新的稳定分支。 + +1. 🌳 **建立分支**,从合适的分支建立一个新功能分支。 + * 请参见这里的 [编码风格](#编码风格)。 + * *主要* 功能应当始终提交合并到 `master` 分支,该分支包含即将推出的 Flarum 版本。 + * *重要的*功能应该总是被提交到`主分支`,该分支包含即将发布的 Flarum 版本。 + * 在内部,我们使用 `<姓名首字母缩写>/<简短描述>` 的分支命名方案(例如:`tz/refactor-frontend`)。 + +2. 🔨 **编写代码**,编写一些代码。 + * 修复错误或添加功能时,请根据需要添加单元测试。 + +3. 🚦 **测试代码**,测试您的代码。 + * 修复错误或添加功能时,请根据需要添加单元测试。 + * 使用相关包文件夹中的 `vendor/bin/phpunit` 运行测试套件。 + * 查看 [这里 ](extend/testing.md) 来获取更多在Flarum中测试的信息。 + +4. 💾 **提交代码**,并附上一条描述性信息。 + * 如果您的修改解决了一个现有的 Issue(通常情况下应该是这样),请在新行加上「Fixes #123」,其中 123 是 Issue 的编号。 + * 请务必按照 [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) 规范提交。 + * *修复*提交应该描述被修复的问题,而不是如何修复该问题。 + +5. 🎁 **提交 PR**,在 GitHub 上提交一个 Pull Request。 + * 填写 Pull Request 模板。 + * 如果您的更改是视觉上的,请附上一张截图或 GIF 来演示变更。 + * 请不要包含 JavaScript `dist` 文件。 这些文件会在合并时自动编译。 + +6. 🤝 **合作共赢**,等待 Flarum 团队批准您的请求。 + * 团队成员将审核您的代码。 我们可能会提出一些修改、改进或替代方案,但对于一些小的改动,应该很快就会接受您的 Pull Request。 + * 在处理反馈时,请附加 commit,不要覆盖或压缩提交(我们将在合并时压缩)。 + +7. 🕺 **恭喜**,您刚刚向 Flarum 做了贡献。 + +## 开发工具 + +In order to keep the Flarum codebase clean and consistent, we have a number of coding style guidelines that we follow. When in doubt, read the source code. + +Don't worry if your code styling isn't perfect! StyleCI and Prettier will automatically check formatting for every pull request. This allows us to focus on the content of the contribution, not the code style. + +### PHP + +Flarum follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) coding standard and the [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) autoloading standard. On top of this, we conform to a number of [other style rules](https://github.com/flarum/framework/blob/main/.styleci.yml). We use PHP 7 type hinting and return type declarations where possible, and [PHPDoc](https://docs.phpdoc.org/) to provide inline documentation. Try and mimic the style used by the rest of the codebase in your contributions. + +* 命名空间应当是单数(例如:`Flarum\Discussion`,而非 `Flarum\Discussions`) +* 接口命名应当以 `Interface` 结尾(例如:`MailableInterface`) +* 抽象类命名应当以 `Abstract` 开头(例如:`AbstractModel`) +* Trait 命名应当以 `Trait` 结尾(例如:`ScopeVisibilityTrait`) + +### JavaScript + +Flarum's JavaScript mostly follows the [Airbnb Style Guide](https://github.com/airbnb/javascript). We use [ESDoc](https://esdoc.org/manual/tags.html) to provide inline documentation. + +### 翻译 + +**Columns** should be named according to their data type: +* DATETIME 或 TIMESTAMP:`{动词}_at`(例如:created_at,read_at)或 `{动词}_until`(例如:suspended_until) +* INT 用于计数:`{名词}_count`(例如:comment_count,word_count) +* 外键:`{动词}_{实体对象}_id`(例如:hidden_user_id) + * 动词可以使用具有相同意义的主键等替代(例如:帖子作者可以是 `user_id`) +* 布尔值:`is_{形容词}`(例如:is_locked) + +**Tables** should be named as follows: +* 使用复数形式(`discussions`) +* 多个单词之间用下划线分隔(`access_tokens`) +* 对于关系表,请将两个表名用单数的形式连接起来,并按字母顺序排列。 (例如:`discussion_user`) + +### CSS + +Flarum's CSS classes roughly follow the [SUIT CSS naming conventions](https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md) using the format `.ComponentName-descendentName--modifierName`. + +### Translations + +We use a [standard key format](/extend/i18n.md#appendix-a-standard-key-format) to name translation keys descriptively and consistently. + +## 贡献者许可协议 + +By contributing your code to Flarum you grant the Flarum Foundation (Stichting Flarum) a non-exclusive, irrevocable, worldwide, royalty-free, sublicensable, transferable license under all of Your relevant intellectual property rights (including copyright, patent, and any other rights), to use, copy, prepare derivative works of, distribute and publicly perform and display the Contributions on any licensing terms, including without limitation: (a) open source licenses like the MIT license; and (b) binary, proprietary, or commercial licenses. Except for the licenses granted herein, You reserve all right, title, and interest in and to the Contribution. + +You confirm that you are able to grant us these rights. You represent that You are legally entitled to grant the above license. If Your employer has rights to intellectual property that You create, You represent that You have received permission to make the Contributions on behalf of that employer, or that Your employer has waived such rights for the Contributions. + +You represent that the Contributions are Your original works of authorship, and to Your knowledge, no other person claims, or has the right to claim, any right in any invention or patent related to the Contributions. You also represent that You are not legally obligated, whether by entering into an agreement or otherwise, in any way that conflicts with the terms of this license. + +The Flarum Foundation acknowledges that, except as explicitly described in this Agreement, any Contribution which you provide is on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/README.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/README.md new file mode 100644 index 000000000..a1b69784c --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/README.md @@ -0,0 +1,40 @@ +- - - +slug: /extend +- - - + +# 扩展 Flarum + +Flarum 是简约的,同时也是高度可扩展的。 实际上,Flarum 附带的大部分功能都是扩展程序。 + +这使得 Flarum 具有高度的可定制性。 用户可以随时禁用任何不需要的功能,或者安装其他扩展程序,打造完美的社区论坛。 + +为了实现这种扩展性,Flarum 构建时使用了丰富的 API 和扩展点 您只要掌握一些编程知识,就可以利用这些 API 来添加几乎所有您想拥有的功能。 本章节将为您介绍 Flarum 的工作方式和如何使用 API,以便您构建自己的扩展程序。 + +## 核心 vs 扩展 + +Flarum 的核心和扩展之间有清晰的界限吗? 为什么有些功能核心里有,而有些又没有? 了解这种区别非常有助于我们在 Flarum 的生态系统中保持一致性和高质量。 + +**Flarum 的核心** 不会拥有所有功能。 相反,它是一个基础或一个框架,为扩展提供了一个可靠的基础。 它只包含对论坛至关重要的基本的、未提出意见的功能:讨论、帖子、用户群组和通知。 + +**捆绑扩展** 又称原生扩展,是与核心打包到一块、默认启用的。 它们和其他扩展一样,可以被禁用或卸载。 我们的想法是使其具有良好的通用性、可配置性,以满足大多数人的需求,因此,捆绑扩展无法满足一切使用需求。 + +**第三方扩展** 由他人开发,Flarum 团队也不会提供官方支持。 他们大多用于解决特定的需求。 + +如果您想要解决核心或现有捆绑扩展的 Bug 或功能缺陷,我们建议您 *直接为对应的项目贡献代码*,这要比分散精力去开发一个新的第三方扩展更合适一些。 您可以在 [Flarum 社区](https://discuss.flarum.org/) 发帖与 Flarum 开发者交流有关事宜。 + +## 资料推荐 + +- [本文档](start.md) +- [扩展开发小贴士](https://discuss.flarum.org/d/5512-extension-development-tips) +- [开发者讲解:扩展开发的工作流程](https://github.com/flarum/cli) +- [扩展名空间小贴士](https://discuss.flarum.org/d/6320-extension-developers-show-us-your-workflow) +- [Mithril js 文档](https://discuss.flarum.org/d/9625-flarum-extension-namespacing-tips) +- [Laravel API 文档](https://mithril.js.org/) +- [Flarum API 文档](https://laravel.com/api/8.x/) +- [Flarum API 文档](https://api.flarum.org) +- [ES6 代码速查表](https://github.com/DrkSephy/es6-cheatsheet) + +### 获取帮助 + +- [Flarum 官方开发社区](https://discuss.flarum.org/t/dev) +- [加入 Discord 中的 #extend 频道](https://flarum.org/discord/) diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/admin.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/admin.md new file mode 100644 index 000000000..2f7da8d3b --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/admin.md @@ -0,0 +1,214 @@ +# 后台管理面板 + +Beta 15引入了一个完全重新设计的管理面板和前端API。 现在比以往任何时候都更容易为您的扩展添加设置或权限。 + +在测试版15之前,扩展设置要么在 `设置模式` 中添加,要么为更复杂的设置添加了一个新的页面。 现在,每个扩展程序都有一个包含信息、设置和扩展程序自身权限的页面。 + +您可以简单地注册设置,扩展页面 [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage),或完全自定义页面。 + +## 扩展数据API + +这个新的 API 允许您用极少的代码添加设置到扩展中。 + +### 告诉API您扩展的信息 + +在注册任何内容之前,您需要告诉`ExtensionData`它将为哪个扩展获取数据。 + +只需在`app.extensionData`上运行`for`函数,并传入扩展的id。 要找到您的扩展id,取编写器名称并用破折号替换任何斜杠(例如:'fof/merge-discussion '变成'fof-merge-discussion ')。 带有`flarum-`和`flarum-ext-`的扩展将从名称中省略这些内容(例如:'webbinaro/flarum-calendar'变成'webbinaro-calendar')。 + +对于下面的例子,我们将使用虚构的扩展名'acme/interstellar': + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') +}); +``` + +完成后,您可以开始添加设置和权限。 + +:::注意 + +`ExtensionData`上的所有注册函数都是可链接的,这意味着您可以一个接一个地调用它们而无需再次运行`for` 。 + +::: + +### 注册设置 + +对于简单的项目,建议使用这种方式添加设置字段。 一般来说,如果您只需要在设置表中存储东西,这对您来说应该足够了。 + +要添加字段,请在`app.extensionData`的`for`之后调用`registerSetting`函数,并传递一个“设置对象”作为第一个参数。 在场景背后的 `ExtensionData` 实际上将您的设置变成了一个 [`ItemLis`](https://api.docs.flarum.org/js/master/class/src/common/utils/itemlist.ts~itemlist)您可以传递优先级编号作为第二个参数。 + +Here's an example with a switch (boolean) item: + +```js + +app.initializers.add('interstellar', function(app){ + + app.extensionData + .for('acme-interstellar') + registerSetting( + { + setting: 'acme-interstellar.coordinates', //这是数据库设置表中保存设置的键值。 + label: app.translator.trans('acme-interstellar.admin.coordinates_label'), // The label to be shown letting the admin know what the setting does. + help: app.translator.trans('acme-interstellar.admin.coordinates_help'), // Optional help text where a longer explanation of the setting can go. + type: 'boolean', // 这是什么类型的设置,有效选项包括:布尔、文本(或任何其他" " 标记类型)和选择。 + }, + 30 // 选择: 优先 + ) +}); +``` + +如果您使用 `type: 'select'` 设置对象看起来有一点不同: + +```js +{ + setting: 'acme-interstellar.fuel_type', + label: app.translator.trans('acme-interstellar.admin.fuel_type_label'), + type: 'select', + options: { + 'LOH': 'Liquid Fuel', // 该对象中的键作为设置项,存储在数据库中,值是管理员将看到的标签(如果翻译在上下文中有意义,请记住使用翻译)。 + 'RDX': 'Solid Fuel', + }, + default: 'LOH', +} +``` + +Also, note that additional items in the setting object will be used as component attrs. This can be used for placeholders, min/max restrictions, etc: + +```js +{ + setting: 'acme-interstellar.crew_count', + label: app.translator.trans('acme-interstellar.admin.crew_count_label'), + type: 'number', + min: 1, + max: 10 +} +``` + +If you want to add something to the settings like some extra text or a more complicated input, you can also pass a callback as the first argument that returns JSX. This callback will be executed in the context of [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) and setting values will not be automatically serialized. + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerSetting(function () { + if (app.session.user.username() === 'RocketMan') { + + return ( +
+

{app.translator.trans('acme-interstellar.admin.you_are_rocket_man_label')}

+ +
+ ); + } + }) +}); +``` + +### Registering Permissions + +New in beta 15, permissions can now be found in 2 places. Now, you can view each extension's individual permissions on their page. All permissions can still be found on the permissions page. + +In order for that to happen, permissions must be registered with `ExtensionData`. This is done in a similar way to settings, call `registerPermission`. + +Arguments: + * Permission object + * What type of permission - see [`PermissionGrid`](https://api.docs.flarum.org/js/master/class/src/admin/components/permissiongrid.js~permissiongrid)'s functions for types (remove items from the name) + * `ItemList` priority + +Back to our favorite rocket extension: + +```js +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerPermission( + { + icon: 'fas fa-rocket', // Font-Awesome Icon + label: app.translator.trans('acme-interstellar.admin.permissions.fly_rockets_label'), // Permission Label + permission: 'discussion.rocket_fly', // Actual permission name stored in database (and used when checking permission). + tagScoped: true, // Whether it be possible to apply this permission on tags, not just globally. Explained in the next paragraph. + }, + 'start', // Category permission will be added to on the grid + 95 // Optional: Priority + ); +}); +``` + +If your extension interacts with the [tags extension](https://github.com/flarum/tags) (which is fairly common), you might want a permission to be tag scopable (i.e. applied on the tag level, not just globally). You can do this by including a `tagScoped` attribute, as seen above. Permissions starting with `discussion.` will automatically be tag scoped unless `tagScoped: false` is indicated. + +To learn more about Flarum permissions, see [the relevant docs](permissions.md). + +### Chaining Reminder + +Remember these functions can all be chained like: + +```js +app.extensionData + .for('acme-interstellar') + .registerSetting(...) + .registerSetting(...) + .registerPermission(...) + .registerPermission(...); +``` + +### Extending/Overriding the Default Page + +Sometimes you have more complicated settings that mess with relationships, or just want the page to look completely different. In this case, you will need to tell `ExtensionData` that you want to provide your own page. Note that `buildSettingComponent`, the util used to register settings by providing a descriptive object, is available as a method on `ExtensionPage` (extending from `AdminPage`, which is a generic base for all admin pages with some util methods). + +Create a new class that extends the `Page` or `ExtensionPage` component: + +```js +import ExtensionPage from 'flarum/admin/components/ExtensionPage'; + +export default class StarPage extends ExtensionPage { + content() { + return ( +

Hello from the settings section!

+ ) + } +} + +``` + +Then, simply run `registerPage`: + +```js + +import StarPage from './components/StarPage'; + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerPage(StarPage); +}); +``` + +This page will be shown instead of the default. + +您可以扩展 [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) 或扩展基本 `Page` 并设计自己的页面! + +## Composer.json Metadata + +In beta 15, extension pages make room for extra info which is pulled from extensions' composer.json. + +For more information, see the [composer.json schema](https://getcomposer.org/doc/04-schema.md). + +| Description | 在composer.json 中的位置 | +| ---------------------------------- | ------------------------------------------------------------ | +| discuss.flarum.org discussion link | "forum" key inside "support" | +| Documentation | "docs" key inside "support" | +| Support (email) | "email" key inside "support" | +| Website | "homepage" key | +| Donate | "funding" key block (Note: Only the first link will be used) | +| Source | "source" key inside "support" | diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md new file mode 100644 index 000000000..354ef8d8e --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/api-throttling.md @@ -0,0 +1,58 @@ +# API 调节器 + +Flarum comes with a builtin `Flarum\Api\Middleware\ThrottleApi` [middleware](middleware.md) for throttling requests to the API. This runs on every API route, and extensions can add their own custom logic to throttle requests. + +:::caution Forum Routes + +Some forum routes (login, register, forgot password, etc) work by calling an API route under the surface. The `ThrottleApi` middleware does not currently run for these requests, but that is planned for the future. + +::: + +## Custom Throttlers + +The format for a custom throttler is extremely simple: all you need is a closure or invokable class that takes the current request as an argument, and returns one of: + +- `false`: This explicitly bypasses throttling for this request, overriding all other throttlers +- `true`: This marks the request as to be throttled. +- `null`: This means that this throttler doesn't apply. Any other outputs will be ignored, with the same effect as `null`. + +Throttlers will be run on EVERY request, and are responsible for figuring out whether or not they apply. For example, consider Flarum's post throttler: + +```php +use DateTime; +use Flarum\Post\Post; + +function ($request) { + if (! in_array($request->getAttribute('routeName'), ['discussions.create', 'posts.create'])) { + return; + } + + $actor = $request->getAttribute('actor'); + + if ($actor->can('postWithoutThrottle')) { + return false; + } + + if (Post::where('user_id', $actor->id)->where('created_at', '>=', new DateTime('-10 seconds'))->exists()) { + return true; + } +}; +``` + +Throttlers can be added or removed via the `ThrottleApi` middleware in `extend.php`. For example: + +```php +set('throttleAll', function () { + return false; + }) + ->remove('bypassThrottlingAttribute'), + // Other extenders +]; +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/api.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/api.md new file mode 100644 index 000000000..f4451d0c4 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/api.md @@ -0,0 +1,353 @@ +# 接口与数据流 + +在[上一篇文章中](models.md), 我们学习了Flarum是如何通过模型与数据交互的。 在这里,我们将学习如何将数据从数据库到 JSON-API 再到前端,然后再返回。 + +:::info + +To use the built-in REST API as part of an integration, see [Consuming the REST API](../rest-api.md). + +::: + +## API请求生命周期 + +Before we go into detail about how to extend Flarum's data API, it's worth thinking about the lifecycle of a typical API request: + +![Flarum API Flowchart](/en/img/api_flowchart.png) + +1. An HTTP request is sent to Flarum's API. Typically, this will come from the Flarum frontend, but external programs can also interact with the API. Flarum's API mostly follows the [JSON:API](https://jsonapi.org/) specification, so accordingly, requests should follow [said specification](https://jsonapi.org/format/#fetching). +2. The request is run through [middleware](middleware.md), and routed to the proper controller. You can learn more about controllers as a whole on our [routes and content documentation](routes.md). Assuming the request is to the API (which is the case for this section), the controller that handles the request will be a subclass of `Flarum\Api\AbstractSerializeController`. +3. Any modifications done by extensions to the controller via the [`ApiController` extender](#extending-api-controllers) are applied. This could entail changing sort, adding includes, changing the serializer, etc. +4. The `$this->data()` method of the controller is called, yielding some raw data that should be returned to the client. Typically, this data will take the form of a Laravel Eloquent model collection or instance, which has been retrieved from the database. 也就是说,只要控制器的序列化器可以处理,数据可以是任何东西。 Each controller is responsible for implementing its own `data` method. 请注意,对于 `PATCH`、`POST` 和 `DELETE` 请求,`data` 将执行相关操作,并返回修改后的模型实例。 +5. That data is run through any pre-serialization callbacks that extensions register via the [`ApiController` extender](#extending-api-controllers). +6. The data is passed through a [serializer](#serializers), which converts it from the backend, database-friendly format to the JSON:API format expected by the frontend. 它还会附加任何相关对象,这些对象会通过各自的序列化器运行。 As we'll explain below, extensions can [add / override relationships and attributes](#attributes-and-relationships) at the serialization level. +7. The serialized data is returned as a JSON response to the frontend. +8. 如果请求是通过 Flarum 前端的 `Store`发出的,返回的数据 (包括任何相关对象) 将作为 [frontend models](#frontend-models)存储在前端存储中。 + +## API Endpoints + +We learned how to use models to interact with data, but we still need to get that data from the backend to the frontend. We do this by writing API Controller [routes](routes.md), which implement logic for API endpoints. + +As per the JSON:API convention, we'll want to add separate endpoints for each operation we support. Common operations are: + +- Listing instances of a model (possibly including searching/filtering) +- Getting a single model instance +- Creating a model instance +- Updating a model instance +- Deleting a single model instance + +We'll go over each type of controller shortly, but once they're written, you can add these five standard endpoints (or a subset of them) using the `Routes` extender: + +```php + (new Extend\Routes('api')) + ->get('/tags', 'tags.index', ListTagsController::class) + ->get('/tags/{id}', 'tags.show', ShowTagController::class) + ->post('/tags', 'tags.create', CreateTagController::class) + ->patch('/tags/{id}', 'tags.update', UpdateTagController::class) + ->delete('/tags/{id}', 'tags.delete', DeleteTagController::class) +``` + +:::caution + +Paths to API endpoints are not arbitrary! To support interactions with frontend models: + +- 对于获取/更新/删除,路径应为 `/prefix/{id}`;对于列表/创建,路径应为 `/prefix`。 +- the prefix (`tags` in the example above) must correspond to the JSON:API model type. You'll also use this model type in your serializer's `$type` attribute, and when registering the frontend model (`app.store.models.TYPE = MODEL_CLASS`). +- The methods must match the example above. + +Also, remember that route names (`tags.index`, `tags.show`, etc) must be unique! + +::: + +The `Flarum\Api\Controller` namespace contains a number of abstract controller classes that you can extend to easily implement your JSON-API resources. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically create your endpoint controllers: +```bash +$ flarum-cli make backend api-controller +``` + +::: + +### Listing Resources + +For the controller that lists your resource, extend the `Flarum\Api\Controller\AbstractListController` class. At a minimum, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a collection of models. The `data` method accepts the `Request` object and the tobscure/json-api `Document`. + +```php +use Flarum\Api\Controller\AbstractListController; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ListTagsController extends AbstractListController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + return Tag::all(); + } +} +``` + +#### Pagination + +You can allow the number of resources being **listed** to be customized by specifying the `limit` and `maxLimit` properties on your controller: + +```php + // The number of records included by default. + public $limit = 20; + + // The maximum number of records that can be requested. + public $maxLimit = 50; +``` + +You can then extract pagination information from the request using the `extractLimit` and `extractOffset` methods: + +```php +$limit = $this->extractLimit($request); +$offset = $this->extractOffset($request); + +return Tag::skip($offset)->take($limit); +``` + +To add pagination links to the JSON:API document, use the `Document::addPaginationLinks` method. + +#### Sorting + +You can allow the sort order of resources being **listed** to be customized by specifying the `sort` and `sortField` properties on your controller: + +```php + // The default sort field and order to use. + public $sort = ['name' => 'asc']; + + // The fields that are available to be sorted by. + public $sortFields = ['firstName', 'lastName']; +``` + +You can then extract sorting information from the request using the `extractSort` method. This will return an array of sort criteria which you can apply to your query: + +```php +use Illuminate\Support\Str; + +// ... + +$sort = $this->extractSort($request); +$query = Tag::query(); + +foreach ($sort as $field => $order) { + $query->orderBy(Str::snake($field), $order); +} + +return $query->get(); +``` + +#### 搜索 + +Read our [searching and filtering](search.md) guide for more information! + +### Showing a Resource + +For the controller that shows a single resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the list controller, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a single model. We'll learn about serializers [in just a bit](#serializers). + +```php +use Flarum\Api\Controller\AbstractShowController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ShowTagController extends AbstractShowController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + return Tag::findOrFail($id); + } +} +``` + +### Creating a Resource + +For the controller that creates a resource, extend the `Flarum\Api\Controller\AbstractCreateController` class. This is the same as the show controller, except the response status code will automatically be set to `201 Created`. You can access the incoming JSON:API document body via `$request->getParsedBody()`: + +```php +use Flarum\Api\Controller\AbstractCreateController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class CreateTagController extends AbstractCreateController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $attributes = Arr::get($request->getParsedBody(), 'data.attributes'); + + return Tag::create([ + 'name' => Arr::get($attributes, 'name') + ]); + } +} +``` + +### Updating a Resource + +For the controller that updates a resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the create controller, you can access the incoming JSON:API document body via `$request->getParsedBody()`. + +### Deleting a Resource + +For the controller that deletes a resource, extend the `Flarum\Api\Controller\AbstractDeleteController` class. You only need to implement a `delete` method which enacts the deletion. The controller will automatically return an empty `204 No Content` response. + +```php +use Flarum\Api\Controller\AbstractDeleteController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; + +class DeleteTagController extends AbstractDeleteController +{ + protected function delete(Request $request) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + Tag::findOrFail($id)->delete(); + } +} +``` + +### Including Relationships + +To include relationships when **listing**, **showing**, or **creating** your resource, specify them in the `$include` and `$optionalInclude` properties on your controller: + +```php + // The relationships that are included by default. + public $include = ['user']; + + // Other relationships that are available to be included. + public $optionalInclude = ['discussions']; +``` + +You can then get a list of included relationships using the `extractInclude` method. This can be used to eager-load the relationships on your models before they are serialized: + +```php +$relations = $this->extractInclude($request); + +return Tag::all()->load($relations); +``` + +### Extending API Controllers + +It is possible to customize all of these options on _existing_ API controllers too via the `ApiController` extender + +```php +use Flarum\Api\Event\WillGetData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->setSerializer(MyDiscussionSerializer::class) + ->addInclude('user') + ->addOptionalInclude('posts') + ->setLimit(20) + ->setMaxLimit(50) + ->setSort(['name' => 'asc']) + ->addSortField('firstName') + ->prepareDataQuery(function ($controller) { + // Add custom logic here to modify the controller + // before data queries are executed. + }) +] +``` + +The `ApiController` extender can also be used to adjust data before serialization + +```php +use Flarum\Api\Event\WillSerializeData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->prepareDataForSerialization(function ($controller, $data, $request, $document) { + $data->load('myCustomRelation'); + }), +] +``` + +## Serializers + +Before we can send our data to the frontend, we need to convert it to JSON:API format so that it can be consumed by the frontend. You should become familiar with the [JSON:API specification](https://jsonapi.org/format/). Flarum's JSON:API layer is powered by the [tobscure/json-api](https://github.com/tobscure/json-api) library. + +A serializer is just a class that converts some data (usually [Eloquent models](models.md#backend-models)) into JSON:API. Serializers serve as intermediaries between backend and frontend models: see the [model documentation](models.md) for more information. To define a new resource type, create a new serializer class extending `Flarum\Api\Serializer\AbstractSerializer`. You must specify a resource `$type` and implement the `getDefaultAttributes` method which accepts the model instance as its only argument: + +```php +use Flarum\Api\Serializer\AbstractSerializer; +use Flarum\Api\Serializer\UserSerializer; + +class DiscussionSerializer extends AbstractSerializer +{ + protected $type = 'discussions'; + + protected function getDefaultAttributes($discussion) + { + return [ + 'title' => $discussion->title, + ]; + } +} +``` + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically create your serializer: +```bash +$ flarum-cli make backend api-serializer +``` + +::: + +### Attributes and Relationships + +You can also specify relationships for your resource. Simply create a new method with the same name as the relation on your model, and return a call to `hasOne` or `hasMany` depending on the nature of the relationship. You must pass in the model instance and the name of the serializer to use for the related resources. + +```php + protected function user($discussion) + { + return $this->hasOne($discussion, UserSerializer::class); + } +``` + +### Extending Serializers + +To add **attributes** and **relationships** to an existing resource type, use the `ApiSerializer` extender: + +```php +use Flarum\Api\Serializer\UserSerializer; + +return [ + (new Extend\ApiSerializer(UserSerializer::class)) + // One attribute at a time + ->attribute('firstName', function ($serializer, $user, $attributes) { + return $user->first_name + }) + // Multiple modifications at once, more complex logic + ->mutate(function($serializer, $user, $attributes) { + $attributes['someAttribute'] = $user->someAttribute; + if ($serializer->getActor()->can('administrate')) { + $attributes['someDate'] = $serializer->formatDate($user->some_date); + } + + return $attributes; + }) + // API relationships + ->hasOne('phone', PhoneSerializer::class) + ->hasMany('comments', CommentSerializer::class), +] +``` + +### Non-Model Serializers and `ForumSerializer` + +Serializers don't have to correspond to Eloquent models: you can define JSON:API resources for anything. For instance, Flarum core uses the [`Flarum\Api\Serializer\ForumSerializer`](https://api.docs.flarum.org/php/master/flarum/api/serializer/forumserializer) to send an initial payload to the frontend. This can include settings, whether the current user can perform certain actions, and other data. Many extensions add data to the payload by extending the attributes of `ForumSerializer`. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/assets.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/assets.md new file mode 100644 index 000000000..16b401fc3 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/assets.md @@ -0,0 +1,7 @@ +# Extension Assets + +Some extensions might want to include assets like images or JSON files in their source code (note that this is not the same as uploads, which would probably require a [filesystem disk](filesystem.md)). + +This is actually very easy to do. Just create an `assets` folder at the root of your extension, and place any asset files there. Flarum will then automatically copy those files to its own `assets` directory (or other storage location if [one is offered by extensions](filesystem.md)) every time the extension is enabled or [`php flarum assets:publish`](../console.md) is executed. + +If using the default storage driver, assets will be available at `https://FORUM_URL/assets/extensions/EXTENSION_ID/file.path`. However, since other extensions might use remote filesystems, we recommend serializing the url to assets you need in the backend. See [Flarum's serialization of the logo and favicon URLs](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Serializer/ForumSerializer.php#L85-L86) for an example. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md new file mode 100644 index 000000000..3e56666d0 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/authorization.md @@ -0,0 +1,206 @@ +# 身份认证 + +与其他框架类似,Flarum 可以将指定的操作和内容访问权限授权给特定的用户。 这方面有两套平行的系统: + +- 授权程序决定用户是否可以采取某些操作。 +- 可见性作用域可以应用于数据库查询,有效地限制用户能够访问的记录。 这记录在我们的 [模型可见性](model-visibility.md) 文档中。 + +## 认证流程 + +The authorization process is used to check whether a person is allowed to perform certain actions. For instance, we want to check if a user is authorized before they: + +- Access the admin dashboard +- Start a discussion +- Edit a post +- Update another user's profile + +Each of these is determined by unique criteria: in some cases a flag is sufficient; otherwise, we might need custom logic. + +## How It Works + +Authorization queries are made with 3 parameters, with logic contained in [`Flarum\User\Gate`](https://api.docs.flarum.org/php/master/flarum/user/access/gate): + +1. The actor: the user attempting to perform the action +2. The ability: a string representing the action the actor is attempting +3. The arguments: usually an instance of a database model which is the subject of the attempted ability, but could be anything. + +First, we run the entire request (all three parameters) through all [policies](#policies) registered by extensions and core. Policies are blocks of logic provided by core and extensions that determine whether the actor can perform the ability on the arguments. Policies can return one of the following: + +- `Flarum\User\Access\AbstractPolicy::ALLOW` (via `$this->allow()`) +- `Flarum\User\Access\AbstractPolicy::DENY` (via `$this->deny()`) +- `Flarum\User\Access\AbstractPolicy::FORCE_ALLOW` (via `$this->forceAllow()`) +- `Flarum\User\Access\AbstractPolicy::FORCE_DENY` (via `$this->forceDeny()`) + +Policy results are considered in the priority `FORCE_DENY` > `FORCE_ALLOW` > `DENY` > `ALLOW`. For example, if a single policy returns `FORCE_DENY`, all other policies will be ignored. If one policy returns `DENY` and 10 policies return `ALLOW`, the request will be denied. This allows decisions to be made regardless of the order in which extensions are booted. Note that policies are extremely powerful: if access is denied at the policy stage, that will override group permissions and even admin privileges. + +Secondly, if all policies return null (or don't return anything), we check if the user is in a group that has a permission equal to the ability (note that both permissions and abilities are represented as strings). If so, we authorize the action. See our [Groups and Permissions documentation](permissions.md) for more information on permissions. + +Then, if the user is in the admin group, we will authorize the action. + +Finally, as we have exhausted all checks, we will assume that the user is unauthorized and deny the request. + +## How To Use Authorization + +Flarum's authorization system is accessible through public methods of the `Flarum\User\User` class. The most important ones are listed below; others are documented in our [PHP API documentation](https://api.docs.flarum.org/php/master/flarum/user/user). + + +In this example, we will use `$actor` as an instance of `Flarum\User\User`, `'viewForum'` and `'reply'` as examples of abilities, and `$discussion` (instance of `Flarum\Discussion\Discussion`) as an example argument. + +```php +// Check whether a user can perform an action. +$canDoSomething = $actor->can('viewForum'); + +// Check whether a user can perform an action on a subject. +$canDoSomething = $actor->can('reply', $discussion); + +// Raise a PermissionDeniedException if a user cannot perform an action. +$actor->assertCan('viewForum'); +$actor->assertCan('reply', $discussion); + +// Raise a NotAuthenticatedException if the user is not logged in. +$actor->assertRegistered(); + +// Raise a PermissionDeniedException if the user is not an admin. +$actor->assertAdmin(); + +// Check whether one of the user's groups have a permission. +// WARNING: this should be used with caution, as it doesn't actually +// run through the authorization process, so it doesn't account for policies. +// It is, however, useful in implementing custom policies. +$actorHasPermission = $actor->hasPermission(`viewForum`); +``` + +## Custom Policies + +Policies allow us to use custom logic beyond simple groups and permissions when evaluating authorization for an ability with a subject. For instance: + +- We want to allow users to edit posts even if they aren't moderators, but only their own posts. +- Depending on settings, we might allow users to rename their own discussions indefinitely, for a short period of time after posting, or not at all. + +As described [above](#how-it-works), on any authorization check, we query all policies registered for the target's model, or any parent classes of the target's model. If no target is provided, any policies registered as `global` will be applied. + +So, how does a policy get "checked"? + +First, we check if the policy class has a method with the same name as the ability being evaluated. If so, we run it with the actor and subject as parameters. If that method returns a non-null value, we return that result. Otherwise, we continue to the next step (not necessarily the next policy). + +Then, we check if the policy class has a method called `can`. If so, we run it with the actor, ability, and subject, and return the result. + +If `can` doesn't exist or returns null, we are done with this policy, and we proceed to the next one. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate policies: +```bash +$ flarum-cli make backend policy +``` + +::: + +### Example Policies + +Let's take a look at an example policy from [Flarum Tags](https://github.com/flarum/tags/blob/master/src/Access): + +```php +is_restricted) { + return $actor->hasPermission('tag'.$tag->id.'.startDiscussion') ? $this->allow() : $this->deny(); + } + } + + /** + * @param User $actor + * @param Tag $tag + * @return bool|null + */ + public function addToDiscussion(User $actor, Tag $tag) + { + return $this->startDiscussion($actor, $tag); + } +} +``` + +We can also have global policies, which are run when `$user->can()` is called without a target model instance. Again from Tags: + +```php +settings = $settings; + } + + /** + * @param Flarum\User\User $actor + * @param string $ability + * @return bool|void + */ + public function can(User $actor, string $ability) + { + if (in_array($ability, ['viewForum', 'startDiscussion'])) { + $enoughPrimary = count(Tag::getIdsWhereCan($actor, $ability, true, false)) >= $this->settings->get('min_primary_tags'); + $enoughSecondary = count(Tag::getIdsWhereCan($actor, $ability, false, true)) >= $this->settings->get('min_secondary_tags'); + + if ($enoughPrimary && $enoughSecondary) { + return $this->allow(); + } else { + return $this->deny(); + } + } + } +} +``` + +### Registering Policies + +Both model-based and global policies can be registered with the `Policy` extender in your `extend.php` file: + +```php +use Flarum\Extend; +use Flarum\Tags\Tag; +use YourNamespace\Access; + +return [ + // Other extenders + (new Extend\Policy()) + ->modelPolicy(Tag::class, Access\TagPolicy::class) + ->globalPolicy(Access\GlobalPolicy::class), + // Other extenders +]; +``` + +## Frontend Authorization + +Commonly, you'll want to use authorization results in frontend logic. For example, if a user doesn't have permission to see search users, we shouldn't send requests to that endpoint. And if a user doesn't have permission to edit users, we shouldn't show menu items for that. + +Because we can't do authorization checks in the frontend, we have to perform them in the backend, and attach them to serialization of data we're sending. Global permissions (`viewForum`, `viewUserList`) can be included on the `ForumSerializer`, but for object-specific authorization, we may want to include those with the subject object. For instance, when we return lists of discussions, we check whether the user can reply, rename, edit, and delete them, and store that data on the frontend discussion model. It's then accessible via `discussion.canReply()` or `discussion.canEdit()`, but there's nothing magic there: it's just another attribute sent by the serializer. + +For an example of how to attach data to a serializer, see a [similar case for transmitting settings](settings.md#accessing-settings). diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md new file mode 100644 index 000000000..25142b030 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/backend-events.md @@ -0,0 +1,172 @@ +# Backend Events + +Often, an extension will want to react to some events occuring elsewhere in Flarum. For instance, we might want to increment a counter when a new discussion is posted, send a welcome email when a user logs in for the first time, or add tags to a discussion before saving it to the database. These events are known as **domain events**, and are broadcasted across the framework through [Laravel's event system](https://laravel.com/docs/8.x/events). + +For a full list of backend events, see our [API documentation](https://api.docs.flarum.org/php/master/search.html?search=Event). Domain events classes are organized by namespace, usually `Flarum\TYPE\Event`. + + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate event listeners: +```bash +$ flarum-cli make backend event-listener +``` + +::: + +## Listening to Events + +You can attach a listener to an event using the [`Event`](https://api.docs.flarum.org/php/master/flarum/extend/event) [extender](start.md#extenders): + +```php +use Flarum\Extend; +use Flarum\Post\Event\Deleted; +use Symfony\Contracts\Translation\TranslatorInterface; + + +return [ + (new Extend\Event) + ->listen(Deleted::class, function($event) { + // do something here + }) + ->listen(Deleted::class, PostDeletedListener::class) +]; +``` +```php +class PostDeletedListener +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function handle(Deleted $event) + { + // Your logic here + } +} +``` + +As shown above, a listener class can be used instead of a callback. This allows you to [inject dependencies](https://laravel.com/docs/8.x/container) into your listener class via constructor parameters. In this example we resolve a translator instance, but we can inject anything we want/need. + +You can also listen to multiple events at once via an event subscriber. This is useful for grouping common functionality; for instance, if you want to update some metadata on changes to posts: + +```php +use Flarum\Extend; +use Flarum\Post\Event\Deleted; +use Flarum\Post\Event\Saving; +use Symfony\Contracts\Translation\TranslatorInterface; + + +return [ + (new Extend\Event) + ->subscribe(PostEventSubscriber::class), +]; +``` +```php +class PostEventSubscriber +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function subscribe($events) + { + $events->listen(Deleted::class, [$this, 'handleDeleted']); + $events->listen(Saving::class, [$this, 'handleSaving']); + } + + public function handleDeleted(Deleted $event) + { + // Your logic here + } + + public function handleSaving(Saving $event) + { + // Your logic here + } +} +``` + +## Dispatching Events + +Dispatching events is very simple. All you need to do is inject `Illuminate\Contracts\Events\Dispatcher` into your class, and then call its `dispatch` method. For instance: + +```php +use Flarum\Post\Event\Deleted; +use Illuminate\Contracts\Events\Dispatcher; + + +class SomeClass +{ + /** + * @var Dispatcher + */ + protected $events; + + /** + * @param Dispatcher $events + */ + public function __construct(Dispatcher $events) + { + $this->events = $events; + } + + public function someMethod() + { + // Logic + $this->events->dispatch( + new Deleted($somePost, $someActor) + ); + // More Logic + } +} +``` + +## Custom Events + +As an extension developer you can define your own events to allow yourself (or other extensions) to react to events in your extension. Events are generally instances of simple classes (no need to extend anything). When defining a new event, you'll typically want to use public properties, and maybe some methods for convenience of users. For example, if we take a look at `Flarum\Post\Event\Deleted`, it's just a wrapping around some data: + +```php +post = $post; + $this->actor = $actor; + } +} +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/cli.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/cli.md new file mode 100644 index 000000000..7c69594f8 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/cli.md @@ -0,0 +1,15 @@ +# 开发者讲解:扩展开发的工作流程 + +The Flarum development ecosystem is oriented around many small, modules, interacting extensions. This is a very powerful and flexible paradigm, but it also brings the maintenance cost of creating and maintaining all these extensions. + +We've created the Flarum CLI (command line interface) as a tool to help developers by automating some repetitive and menial tasks, and allow them to get into the actual work without much hassle. + +Major updates about Flarum CLI will be published [on this discussion](https://discuss.flarum.org/d/28427-flarum-cli-v10). + +See the [package's readme](https://github.com/flarum/cli#readme) for information on: + +- 安装 +- Usage +- Upgrading +- Available commands +- Some implementation details, if you're interested diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/console.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/console.md new file mode 100644 index 000000000..b61d31e83 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/console.md @@ -0,0 +1,77 @@ +# 控制台 + +除了 Flarum 核心提供的 [默认命令](../console.md),我们还允许扩展程序的开发者添加自定义控制台命令。 + +所有控制台命令开发都是在后端使用 PHP 完成的。 要创建自定义控制台命令,您需要创建一个类实现 `\Flarum\Console\AbstractCommand`。 + +```php +use Flarum\Console\AbstractCommand; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; + +class YourCommand implements AbstractCommand { + protected function configure() + { + $this + ->setName('您的命令名') + ->setDescription('您的命令描述'); + } + protected function fire() + { + // 逻辑实现! + } +} +``` + +:::info [Flarum CLI](https://github.com/flarum/cli) + +:::tip 定时命令 +```bash +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; + +return [ + // 其他扩展器 + (new Extend\Console())->command(CustomCommand::class) + // 其他扩展器 +]; +``` + +::: + +## 注册控制台命令 + +To register console commands, use the `Flarum\Extend\Console` extender in your extension's `extend.php` file: + +```php +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; + +return [ + // Other extenders + (new Extend\Console())->command(CustomCommand::class) + // Other extenders +]; +``` + +## Scheduled Commands + +The `Flarum\Extend\Console`'s `schedule` method allows extension developers to create scheduled commands that run on an interval: + + +```php +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; +use Illuminate\Console\Scheduling\Event; + +return [ + // Other extenders + (new Extend\Console())->schedule('cache:clear', function (Event $event) { + $event->everyMinute(); + }, ['Arg1', '--option1', '--option2']), + // Other extenders +]; +``` + +In the callback provided as the second argument, you can call methods on the [$event object](https://laravel.com/api/8.x/Illuminate/Console/Scheduling/Event.html) to schedule on a variety of frequencies (or apply other options, such as only running on one server). See the [Laravel documentation](https://laravel.com/docs/8.x/scheduling#scheduling-artisan-commands) for more information. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md new file mode 100644 index 000000000..7061d5aa0 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/distribution.md @@ -0,0 +1,40 @@ +# Distribution + +You've written a great extension — and now you want the whole world to be able to use it. This document will take you through the process of distribution, from setting up a Git repository for your extension, to publishing it on Packagist. + +## Setting Up Git + +The first thing you'll need to do is set up a version control system (VCS). The most popular VCS is [Git](https://git-scm.com/). In this guide we'll be using Git, so make sure you have it [installed](https://git-scm.com/downloads) before continuing. If you don't have much Git knowledge, you may want to check out [these learning resources](https://try.github.io/). + +After you have installed Git, you'll need to initialize your repository. You can use `git init` on the command line if you're comfortable, or use a GUI tool like [SourceTree](https://www.sourcetreeapp.com/) or [GitKraken](https://www.gitkraken.com/). + +Then, you'll need an account in a Git hosting server, the most popular being [GitHub](https://github.com) and [GitLab](https://gitlab.com). These will instruct you on how to hook up your local repository with the online "remote" repository. + +## Tagging a Release + +As you are going to be publishing this extension, you'll want to make sure that the information is up to date. Take a minute to revisit `composer.json` and make sure package name, description, and Flarum extension information are all correct. It is recommended to have a `README.md` file in your repository to explain what the extension is, so create one if you haven't already. + +When you're ready to release, commit your extension's files to the repo and tag your first version: + +```bash +git tag v0.1.0 +git push && git push --tags +``` + +## Publishing on Packagist + +Composer packages are published to a Composer repository, usually [Packagist](https://packagist.org/). You will need an account to proceed. + +If this is the first release you are publishing of your extension, you will need to [submit your package](https://packagist.org/packages/submit) using its public repository URL. If your extension is located on GitHub, this URL will look something like `https://github.com/AUTHOR/NAME.git`. + +### Future Releases + +You can set up Packagist to [auto-update packages](https://packagist.org/about#how-to-update-packages). Then for future releases, all you will need to do with Git is commit, tag, and push it to the remote server. + +## Promoting Your Extension + +You will most likely want to create a discussion on the Flarum Community in the [Extensions tag](https://discuss.flarum.org/t/extensions). Other people can install your extension using the following command: + +```bash +composer require vendor/package +``` \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md new file mode 100644 index 000000000..7a8db4f8c --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/extending-extensions.md @@ -0,0 +1,122 @@ +# Extending Extensions + +Flarum extensions aren't just for adding features to core: extensions can extend other extensions! + +:::tip + +To learn how to make your extension extensible, see the [relevant documentation](extensibility.md) + +::: + +## Dependencies + +If your extension relies on another extension, you'll want to ensure that: + +- The other extension is installed and enabled before yours can be. +- The other extension can't be disabled while yours is enabled. +- The other extension is booted before your extension. + +Flarum makes this very easy: just add the other extension to your extension's `composer.json`'s `require` section. + +For example, if you were building a new theme for the Flarum Tags extension, your `composer.json` would look like this: + +```json +{ + // ... + "require": { + "flarum/core": "^0.1.0-beta.15", // Since all extensions need to require core. + "flarum/tags": "^0.1.0-beta.15" // This tells Flarum to treat tags as a dependency of your extension. + }, + // ... +} +``` + +## Optional Dependencies + +Sometimes, extension A might want to extend extension B only if extension B is enabled. In this case, we call B an "Optional Dependency" of A. For instance, a drafts extension might want to add support for saving private discussion drafts, but only if the private discussion extension is enabled. + +The first step here is detecting whether extension B is enabled. In the frontend, this is easy: if extension B does anything in the frontend, its extension ID will appear as a key in the `flarum.extensions` global object. For instance: + +```js +if ('some-extension-id' in flarum.extensions) { + // do something +} +``` + +In the backend, you'll need to inject an instance of `Flarum\Extension\ExtensionManager`, and use its `isEnabled()` method. For instance: + +```php +extensions = $extensions; + } + + public function someMethod() + { + if ($this->extensions->isEnabled('some-extension-id')) { + // do something. + } + } +} +``` + +Generally, if your extension has optional dependencies, you'll want it to be booted after said optional dependencies. You can also do this by specifying composer package names (NOT flarum extension IDs) in an array for the `extra.flarum-extension.optional-dependencies` key of your composer.json. + +For instance: + +```json +{ + // ... + "extra": { + "flarum-extension": { + "optional-dependencies": [ + "flarum/tags" + ] + } + }, + // ... +} +``` + +## Importing from Extensions + +In the backend, you can import the classes you need via regular PHP `use` statements: + +```php + { + // Your Extension Code Here +}) + +export { + // Put all the stuff you want to export here. +} +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md new file mode 100644 index 000000000..ef202b2c7 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/filesystem.md @@ -0,0 +1,129 @@ +# Filesystem + +Flarum core integrates with the filesystem to store and serve assets (like compiled JS/CSS or upload logos/favicons) and avatars. + +Extensions can use Flarum's provided utils for their own filesystem interaction and file storage needs. This system is based around [Laravel's filesystem tools](https://laravel.com/docs/8.x/filesystem), which are in turn based on the [Flysystem library](https://github.com/thephpleague/flysystem). + +## Disks + +Filesystem **disks** represent storage locations, and are backed by storage drivers, which we'll cover later. Flarum core has 2 disks: `flarum-assets` and `flarum-avatars`. + +### Using existing disks + +To access a disk, you'll need to retrieve it from the [Filesystem Factory](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Factory.html). To do so, you should inject the factory contract in your class, and access the disks you need. + +Let's take a look at core's [`DeleteLogoController`](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Controller/DeleteLogoController.php#L19-L58) for an example: + +```php +settings = $settings; + $this->uploadDir = $filesystemFactory->disk('flarum-assets'); + } + + /** + * {@inheritdoc} + */ + protected function delete(ServerRequestInterface $request) + { + RequestUtil::getActor($request)->assertAdmin(); + + $path = $this->settings->get('logo_path'); + + $this->settings->set('logo_path', null); + + if ($this->uploadDir->exists($path)) { + $this->uploadDir->delete($path); + } + + return new EmptyResponse(204); + } +} +``` + +The object returned by `$filesystemFactory->disk(DISK_NAME)` implements the [Illuminate\Contracts\Filesystem\Cloud](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Cloud.html) interface, and can be used to create/get/move/delete files, and to get the URL to a resource. + +### Declaring new disks + +Some extensions will want to group their resources / uploads onto a custom disk as opposed to using `flarum-assets` or `flarum-avatars`. + +This can be done via the `Filesystem` extender: + +```php +use Flarum\Extend; + +return [ + (new Extend\Filesystem) + ->disk('flarum-uploads', function (Paths $paths, UrlGenerator $url) { + return [ + 'root' => "$paths->public/assets/uploads", + 'url' => $url->to('forum')->path('assets/uploads') + ]; + }); +``` + +Since all disks use the local filesystem by default, you'll need to provide a base path and base URL for the local filesystem. + +The config array can contain other entries supported by [Laravel disk config arrays](https://laravel.com/docs/8.x/filesystem#configuration). The `driver` key should not be provided, and will be ignored. + +## Storage drivers + +Flarum selects the active driver for each disk by checking the `disk_driver.DISK_NAME` key in the [settings repository](settings.md) and [config.php file](../config.md). If no driver is configured, or the configured driver is unavailable, Flarum will default to the `local` driver. + +You can define new storage drivers by implementing the [`Flarum\Filesystem\DriverInterface` interface](https://github.com/flarum/framework/blob/main/framework/core/src/Filesystem/DriverInterface.php#L16), and registering it via the `Filesystem` extender: + +```php +use Flarum\Extend; + +return [ + (new Extend\Filesystem) + ->driver('aws-with-cdn', AwsWithCdnDriver::class); +``` + +Filesystem storage drivers are a very powerful tool that allows you to completely customize file storage locations, attach arbitrary CDNs, and otherwise extend the filesystem / cloud storage integration layer. + +:::danger + +Some drivers might try to index their filesystem every time the driver is instantiated, even if only the `url` method is needed. This can have serious performance implications. In most cases, you'll want to ensure that your driver's `url` method does not ping the remote filesystem. Similarly, the remote filesystem should usually not be accessed until operations are actually executed. + +::: + +## GUI and Admin Configuration + +Flarum does not currently provide a GUI for selecting drivers for disks, or for entering settings for drivers. This might be added in the future. For now, extensions are responsible for providing a GUI for their disks and drivers. + +As noted [above](#storage-drivers), if your extension provides a GUI for selecting drivers for a disk, it should modify the `disk_driver.DISK_NAME` key in settings. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md new file mode 100644 index 000000000..d4ea23b12 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/formatting.md @@ -0,0 +1,42 @@ +# Formatting + +Flarum uses the powerful [s9e TextFormatter](https://github.com/s9e/TextFormatter) library to format posts from plain markup into HTML. You should become familiar with [how TextFormatter works](https://s9etextformatter.readthedocs.io/Getting_started/How_it_works/) before you attempt to extend it. + +In Flarum, post content is formatted with a minimal TextFormatter configuration by default. The bundled **Markdown** and **BBCode** extensions simply enable the respective plugins on this TextFormatter configuration. + +## Configuration + +You can configure the TextFormatter `Configurator` instance, as well as run custom logic during parsing and rendering, using the `Formatter` extender: + +```php +use Flarum\Extend; +use Psr\Http\Message\ServerRequestInterface as Request; +use s9e\TextFormatter\Configurator; +use s9e\TextFormatter\Parser; +use s9e\TextFormatter\Renderer; + +return [ + (new Extend\Formatter) + // Add custom text formatter configuration + ->configure(function (Configurator $config) { + $config->BBCodes->addFromRepository('B'); + }) + // Modify raw text before it is parsed. + // This callback should return the modified text. + ->parse(function (Parser $parser, $context, $text) { + // custom logic here + return $newText; + }) + // Modify the XML to be rendered before rendering. + // This callback should return the new XML. + // For example, in the mentions extension, this is used to + // provide the username and display name of the user being mentioned. + // Make sure that the last $request argument is nullable (or omitted entirely). + ->render(function (Renderer $renderer, $context, $xml, Request $request = null) { + // custom logic here + return $newXml; + }) +]; +``` + +With a good understanding of TextFormatter, this will allow you to achieve anything from simple BBCode tag additions to more complex formatting tasks like Flarum's **Mentions** extension. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/forms.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/forms.md new file mode 100644 index 000000000..af8d74fb6 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/forms.md @@ -0,0 +1,108 @@ +# Forms and Requests + +In this article, we'll go over some frontend tools that are available to us for building and managing forms, as well how to send HTTP requests via Flarum. + +## Form Components + +As with any interactive site, you will likely want to include forms in some pages and modals. Flarum provides some components to make building (and styling!) these forms easier. Please see the linked API documentation for each of these to learn more about its accepted attrs. + +- The [`flarum/common/components/FieldSet` component](https://api.docs.flarum.org/js/master/class/src/common/components/fieldset.js~fieldset) wraps its children in a HTML fieldset tag, with a legend. +- The [`flarum/common/components/Select` component](https://api.docs.flarum.org/js/master/class/src/common/components/select.js~select) is a stylized select input. +- The [`flarum/common/components/Switch`](https://api.docs.flarum.org/js/master/class/src/common/components/switch.js~switch) and [`flarum/common/components/Checkbox` components](https://api.docs.flarum.org/js/master/class/src/common/components/checkbox.js~checkbox) are stylized checkbox input components. Their `loading` attr can be set to `true` to show a loading indicator. +- The [`flarum/common/components/Button` component](https://api.docs.flarum.org/js/master/class/src/common/components/button.js~button) is a stylized button, and is used frequently throughout Flarum. + +You'll typically want to assign logic for reacting to input changes via Mithril's `on*` attrs, not external listeners (as is common with jQuery or plain JS). For example: + +```jsx +import Component from 'flarum/common/Component'; +import FieldSet from 'flarum/common/components/FieldSet'; +import Button from 'flarum/common/components/Button'; +import Switch from 'flarum/common/components/Switch'; + + +class FormComponent extends Component { + oninit(vnode) { + this.textInput = ""; + this.booleanInput = false; + } + + view() { + return ( +
+
+ this.textInput = e.target.value}> + + this.booleanInput = val}> + +
+ +
+ ) + } + + onsubmit() { + // Some form handling logic here + } +} +``` + +Don't forget to use [translations](i18n.md)! + + +## Streams, bidi, and withAttr + +Flarum provides [Mithril's Stream](https://mithril.js.org/stream.html) as `flarum/common/util/Stream`. This is a very powerful reactive data structure, but is most commonly used in Flarum as a wrapper for form data. Its basic usage is: + +```js +import Stream from 'flarum/common/utils/Stream'; + + +const value = Stream("hello!"); +value() === "hello!"; // true +value("world!"); +value() === "world!"; // true +``` + +In Flarum forms, streams are frequently used together with the bidi attr. Bidi stands for bidirectional binding, and is a common pattern in frontend frameworks. Flarum patches Mithril with the [`m.attrs.bidi` library](https://github.com/tobyzerner/m.attrs. This abstracts away input processing in Mithril. For instance: + +```jsx +import Stream from 'flarum/common/utils/Stream'; + +const value = Stream(); + +// Without bidi + value(e.target.value)}> + +// With bidi + +``` + +You can also use the `flarum/common/utils/withAttr` util for simplified form processing. `withAttr` calls a callable, providing as an argument some attr of the DOM element tied to the component in question: + +```jsx +import Stream from 'flarum/common/utils/Stream'; +import withAttr from 'flarum/common/utils/withAttr'; + +const value = Stream(); + +// With a stream + + +// With any callable + { + // Some custom logic here +})}> +``` + +## Making Requests + +In our [models](models.md) documentation, you learned how to work with models, and save model creation, changes, and deletion to the database via the Store util, which is just a wrapper around Flarum's request system, which itself is just a wrapper around [Mithril's request system](https://mithril.js.org/request.html). + +Flarum's request system is available globally via `app.request(options)`, and has the following differences from Mithril's `m.request(options)`: + +- It will automatically attach `X-CSRF-Token` headers. +- It will convert `PATCH` and `DELETE` requests into `POST` requests, and attach a `X-HTTP-Method-Override` header. +- If the request errors, it will show an alert which, if in debug mode, can be clicked to show a full error modal. +- You can supply a `background: false` option, which will run the request synchronously. However, this should almost never be done. + +Otherwise, the API for using `app.request` is the same as that for `m.request`. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md new file mode 100644 index 000000000..396292ad1 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/frontend-pages.md @@ -0,0 +1,218 @@ +# Frontend Pages and Resolvers + +As explained in the [Routes and Content](routes.md#frontend-routes) documentation, we can use Mithril's routing system to show different [components](frontend.md#components) for different routes. Mithril allows you to use any component you like, even a Modal or Alert, but we recommend sticking to component classes that inherit the `Page` component. + +## The Page Component + +We provide `flarum/common/components/Page` as a base class for pages in both the `admin` and `forum` frontends. It has a few benefits: + +- Automatically updates [`app.current` and `app.previous` PageState](#pagestate) when switching from one route to another. +- Automatically closes the modal and drawer when switching from one route to another. +- Applies `this.bodyClass` (if defined) to the '#app' HTML element when the page renders. +- It's also good for consistency's sake to use a common base class for all pages. +- If the page's `scrollTopOnCreate` attribute is set to `false` in `oninit`, the page won't be scrolled to the top when changed. +- If the page's `useBrowserScrollRestoration` is set to `false` in `oninit`, the browser's automatic scroll restoration won't be used on that page. + +Page components work just like any other inherited component. For a (very simple) example: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + view() { + return

Hello!

+ } +} +``` + +### Setting Page as Homepage + +Flarum uses a setting to determine which page should be the homepage: this gives admins flexibility to customize their communities. To add your custom page to the homepage options in Admin, you'll need to extend the `BasicsPage.homePageItems` method with your page's path. + +An example from the [Tags extension](https://github.com/flarum/tags/blob/master/js/src/admin/addTagsHomePageOption.js): + +```js +import { extend } from 'flarum/common/extend'; +import BasicsPage from 'flarum/common/components/BasicsPage'; + +export default function() { + extend(BasicsPage.prototype, 'homePageItems', items => { + items.add('tags', { + path: '/tags', + label: app.translator.trans('flarum-tags.admin.basics.tags_label') + }); + }); +} +``` + +To learn how to set up a path/route for your custom page, see the [relevant documentation](routes.md). + +### Page Titles + +Often, you'll want some custom text to appear in the browser tab's title for your page. For instance, a tags page might want to show "Tags - FORUM NAME", or a discussion page might want to show the title of the discussion. + +To do this, your page should include calls to `app.setTitle()` and `app.setTitleCount()` in its `oncreate` [lifecycle hook](frontend.md) (or when data is loaded, if it pulls in data from the API). + +For example: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + oncreate(vnode) { + super.oncreate(vnode); + + app.setTitle("Cool Page"); + app.setTitleCount(0); + } + + view() { + // ... + } +} + +export default class CustomPageLoadsData extends Page { + oninit(vnode) { + super.oninit(vnode); + + app.store.find("users", 1).then(user => { + app.setTitle(user.displayName()); + app.setTitleCount(0); + }) + } + + view() { + // ... + } +} +``` + +Please note that if your page is [set as the homepage](#setting-page-as-homepage), `app.setTitle()` will clear the title for simplicity. It should still be called though, to prevent titles from previous pages from carrying over. + +## PageState + +Sometimes, we want to get information about the page we're currently on, or the page we've just come from. To allow this, Flarum creates (and stores) instances of [`PageState`](https://api.docs.flarum.org/js/master/class/src/common/states/pagestate.js~pagestate) as `app.current` and `app.previous`. These store: + +- The component class being used for the page +- A collection of data that each page sets about itself. The current route name is always included. + +Data can be set to, and retrieved from, Page State using: + +```js +app.current.set(KEY, DATA); +app.current.get(KEY); +``` + +For example, this is how the Discussion Page makes its [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) instance globally available. + +You can also check the type and data of a page using `PostStreamState`'s `matches` method. For instance, if we want to know if we are currently on a discussion page: + +```jsx +import IndexPage from 'flarum/forum/components/DiscussionPage'; +import DiscussionPage from 'flarum/forum/components/DiscussionPage'; + +// To just check page type +app.current.matches(DiscussionPage); + +// To check page type and some data +app.current.matches(IndexPage, {routeName: 'following'}); +``` + +## Admin Pages + +See the [Admin Dashboard documentation](admin.md) for more information on tools specifically available to admin pages (and how to override the admin page for your extension). + +## Route Resolvers (Advanced) + +[Advanced use cases](https://mithril.js.org/route.html#advanced-component-resolution) can take advantage of Mithril's [route resolver system](https://mithril.js.org/route.html#routeresolver). Flarum actually already wraps all its components in the `flarum/common/resolvers/DefaultResolver` resolver. This has the following benefits: + +- It passes a `routeName` attr to the current page, which then provides it to `PageState` +- It assigns a [key](https://mithril.js.org/keys.html#single-child-keyed-fragments) to the top level page component. When the route changes, if the top level component's key has changed, it will be completely rerendered (by default, Mithril does not rerender components when switching from one page to another if both are handled by the same component). + +### Using Route Resolvers + +There are actually 3 ways to set the component / route resolver when registering a route: + +- the `resolver` key can be used to provide an **instance** of a route resolver. This instance should define which component should be used, and hardcode the route name to be passed into it. This instance will be used without any modifications by Flarum. +- The `resolverClass` key AND `component` key can be used to provide a **class** that will be used to instantiate a route resolver, to be used instead of Flarum's default one, as well as the component to use. Its constructor should take 2 arguments: `(component, routeName)`. +- The `component` key can be used alone to provide a component. This will result in the default behavior. + +For example: + +```js +// See above for a custom page example +import CustomPage from './components/CustomPage'; +// See below for a custom resolver example +import CustomPageResolver from './resolvers/CustomPageResolver'; + +// Use a route resolver instance +app.routes['resolverInstance'] = {path: '/custom/path/1', resolver: { + onmatch: function(args) { + if (!app.session.user) return m.route.SKIP; + + return CustomPage; + } +}}; + +// Use a custom route resolver class +app.routes['resolverClass'] = {path: '/custom/path/2', resolverClass: CustomPageResolver, component: CustomPage}; + +// Use the default resolver class (`flarum/common/resolvers/DefaultResolver`) +app.routes['resolverClass'] = {path: '/custom/path/2', component: CustomPage}; +``` + +### Custom Resolvers + +We strongly encourage custom route resolvers to extend `flarum/common/resolvers/DefaultResolver`. For example, Flarum's `flarum/forum/resolvers/DiscussionPageResolver` assigns the same key to all links to the same discussion (regardless of the current post), and triggers scrolling when using `m.route.set` to go from one post to another on the same discussion page: + +```js +import DefaultResolver from '../../common/resolvers/DefaultResolver'; + +/** + * This isn't exported as it is a temporary measure. + * A more robust system will be implemented alongside UTF-8 support in beta 15. + */ +function getDiscussionIdFromSlug(slug: string | undefined) { + if (!slug) return; + return slug.split('-')[0]; +} + +/** + * A custom route resolver for DiscussionPage that generates the same key to all posts + * on the same discussion. It triggers a scroll when going from one post to another + * in the same discussion. + */ +export default class DiscussionPageResolver extends DefaultResolver { + static scrollToPostNumber: number | null = null; + + makeKey() { + const params = { ...m.route.param() }; + if ('near' in params) { + delete params.near; + } + params.id = getDiscussionIdFromSlug(params.id); + return this.routeName.replace('.near', '') + JSON.stringify(params); + } + + onmatch(args, requestedPath, route) { + if (route.includes('/d/:id') && getDiscussionIdFromSlug(args.id) === getDiscussionIdFromSlug(m.route.param('id'))) { + DiscussionPageResolver.scrollToPostNumber = parseInt(args.near); + } + + return super.onmatch(args, requestedPath, route); + } + + render(vnode) { + if (DiscussionPageResolver.scrollToPostNumber !== null) { + const number = DiscussionPageResolver.scrollToPostNumber; + // Scroll after a timeout to avoid clashes with the render. + setTimeout(() => app.current.get('stream').goToNumber(number)); + DiscussionPageResolver.scrollToPostNumber = null; + } + + return super.render(vnode); + } +} +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md new file mode 100644 index 000000000..d2e0533a7 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/frontend.md @@ -0,0 +1,422 @@ +# 前端开发 + +这个页面描述如何改变Flarum的用户界面—— 添加按钮、文字滚动、和闪耀的文本 🤩 + +[记住](/extend/start.md#architecture), Flarum 的前端是**单页 JavaScript 应用**。 我们不会用到Twig、Blade或任何其他的PHP模板。 后端中存在的少数模板仅用于渲染针对搜索引擎优化的内容。 所有对UI的改动都需要通过JavaScript实现。 + +Flarum有两个分开的前端应用: + +* `forum`,论坛的公共部分,用户在此处创建讨论和帖子。 +* `admin`,论坛的私有部分,你作为论坛管理员在此处对Flarum进行配置。 + +它们共享相同的基础代码,所以只要你学会了如何拓展其中一个,你就能够拓展另一个。 + +:::tip 类型申明(typings)! + +我们在提供新的 TypeScript 支持的同时,提供了一个 [`tsconfig` 配置包](https://www.npmjs.com/package/flarum-tsconfig),你应该将它作为开发依赖安装,以查看我们的类型申明。 请确保你按照[配置包的README文件](https://github.com/flarum/flarum-tsconfig#readme)中的指示配置类型申明支持。 + +::: + +## 转译和文件结构 + +本教程的这个部分讲解释编写拓展的必要文件设置。 再说一次,我们高度推荐使用[Flarum CLI](https://github.com/flarum/cli)来为你创建文件结构。 话虽如此,你仍然应该阅读这一部分以理解文件结构背后的原理。 + +在我们编写JavaScript之前,我们需要配置**转译器**。 这使得我们可以在Flarum核心代码以及拓展中使用[TypeScript](https://www.typescriptlang.org/)和它的魔力。 + +为了进行转译,你需要一个好的工作环境。 不是说在家或者办公室这种环境——你想在厕所写代码我都不管! 我指的是安装在你系统上的工具。 你需要: + +* Node.js和npm ([下载](https://nodejs.org/en/download/)) +* Webpack (`npm install -g webpack`) + +这可能比较麻烦,因为每个人的系统都不一样。 从您正在使用的操作系统,到您已安装的程序版本,到用户访问权限——想想就令人胆寒。 如果你遇上了困难,~~帮我向他问好~~ 上[谷歌](https://google.com)查查是否有人遇到了同样的问题并找到解决方案。 如果找不到,可以去[Flarum社区](https://discuss.flarum.org)或者[Discord群聊](https://flarum.org/discord/)寻求帮助。 + +是时候设置我们的小 JavaScript 转译项目了。 在你的扩展中创建一个新文件夹,名为 `js`,然后再丢进去几个新文件。 一个典型拓展的前端结构是这样的: + +``` +js +├── dist (编译后的js文件保存在此处) +├── src +│ ├── admin +│ └── forum +├── admin.js +├── forum.js +├── package.json +├── tsconfig.json +└── webpack.config.js +``` + +### package.json + +```json +{ + "private": true, + "name": "@acme/flarum-hello-world", + "dependencies": { + "flarum-webpack-config": "^1.0.0", + "webpack": "^4.0.0", + "webpack-cli": "^4.0.0" + }, + "devDependencies": { + "flarum-tsconfig": "^1.0.0" + }, + "scripts": { + "dev": "webpack --mode development --watch", + "build": "webpack --mode production" + } +} +``` + +这是一个标准 JS [包描述文件](https://docs.npmjs.com/files/package.json),被 npm 和 Yarn (JavaScript 包管理器) 使用。 你可以使用它来添加指令、JS依赖和包元数据。 我们不是在真正发布一个npm包:这只是用来收集依赖项。 + +请注意,我们不需要将 `flarum/core` 或任何flarum扩展作为依赖:它们会在Flarum编译所有前端拓展时自动被打包。 + +### webpack.config.js + +```js +const config = require('flarum-webpack-config'); + +module.exports = config(); +``` + +[Webpack](https://webpack.js.org/concepts/)是真正为我们的插件编译并打包所有Javascript (及其依赖) 的系统。 为了使我们的扩展正常工作,它应该使用 [官方的 flarum webpack 配置](https://github.com/flarum/flarum-webpack-config) (在上述例子中展示)。 + +### tsconfig.json + +```json +{ + //使用Flarum的tsconfig作为开始 + "extends": "flarum-tsconfig", + // 这会匹配你的 `src` 文件夹中所有的.ts、.tsx、.d.ts、.js和.jsx文件 + // 同时会让你的Typescript读取论坛核心的全局类型申明 + // 以获取全局命名空间中的`dayjs`和`$` + "include": ["src/**/*", "../vendor/flarum/core/js/dist-typings/@types/**/*"], + "compilerOptions": { + // 这会让类型申明输出到 `dist-typings` + "declarationDir": "./dist-typings", + "baseUrl": ".", + "paths": { + "flarum/*": ["../vendor/flarum/core/js/dist-typings/*"] + } + } +} +``` + +This is a standard configuration file to enable support for Typescript with the options that Flarum needs. + +Always ensure you're using the latest version of this file: https://github.com/flarum/flarum-tsconfig#readme. + +Even if you choose not to use TypeScript in your extension, which is supported natively by our Webpack config, it's still recommended to install the `flarum-tsconfig` package and to include this configuration file so that your IDE can infer types for our core JS. + +To get the typings working, you'll need to run `composer update` in your extension's folder to download the latest copy of Flarum's core into a new `vendor` folder. Remember not to commit this folder if you're using a version control system such as Git. + +You may also need to restart your IDE's TypeScript server. In Visual Studio Code, you can press F1, then type "Restart TypeScript Server" and hit ENTER. This might take a minute to complete. + +### admin.js and forum.js + +These files contain the root of our actual frontend JS. You could put your entire extension here, but that would not be well organized. For this reason, we recommend putting the actual source code in `src`, and having these files just export the contents of `src`. For instance: + +```js +// admin.js +export * from './src/admin'; + +// forum.js +export * from './src/forum'; +``` + +### src + +If following the recommendations for `admin.js` and `forum.js`, we'll want to have 2 subfolders here: one for `admin` frontend code, and one for `forum` frontend code. If you have components, models, utils, or other code that is shared across both frontends, you may want to create a `common` subfolder and place it there. + +Structure for `admin` and `forum` is identical, so we'll just show it for `forum` here: + +``` +src/forum/ +├── components/ +├── models/ +├── utils/ +└── index.js +``` + +`components`, `models`, and `utils` are directories that contain files where you can define custom [components](#components), [models](models.md#frontend-models), and reusable util helper functions. Please note that this is all simply a recommendation: there's nothing forcing you to use this particular file structure (or any other file structure). + +The most important file here is `index.js`: everything else is just extracting classes and functions into their own files. Let's go over a typical `index.js` file structure: + +```js +import { extend, override } from 'flarum/common/extend'; + +// We provide our extension code in the form of an "initializer". +// This is a callback that will run after the core has booted. +app.initializers.add('acme-flarum-hello-world', function(app) { + // Your Extension Code Here + console.log("EXTENSION NAME is working!"); +}); +``` + +We'll go over tools available for extensions below. + +### 导入 + +You should familiarize yourself with proper syntax for [importing js modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import), as most extensions larger than a few lines will split their js into multiple files. + +Pretty much every Flarum extension will need to import *something* from Flarum Core. Like most extensions, core's JS source code is split up into `admin`, `common`, and `forum` folders. You can import the file by prefixing its path in the Flarum core source code with `flarum`. So `admin/components/AdminLinkButton` is available as `flarum/admin/components/AdminLinkButton`, `common/Component` is available as `flarum/common/Component`, and `forum/states/PostStreamState` is available as `flarum/forum/states/PostStreamState`. + +In some cases, an extension may want to extend code from another flarum extension. This is only possible for extensions which explicitly export their contents. + +* `flarum/tags` and `flarum/flags` are currently the only bundled extensions that allow extending their JS. You can import their contents from `flarum/{EXT_NAME}/PATH` (e.g. `flarum/tags/components/TagHero`). +* The process for extending each community extension is different; you should consult documentation for each individual extension. + +### 转译 + +OK, time to fire up the transpiler. Run the following commands in the `js` directory: + +```bash +npm install +npm run dev +``` + +This will compile your browser-ready JavaScript code into the `js/dist/forum.js` file, and keep watching for changes to the source files. Nifty! + +When you've finished developing your extension (or before a new release), you'll want to run `npm run build` instead of `npm run dev`: this builds the extension in production mode, which makes the source code smaller and faster. + +## Asset Registration + +### JavaScript + +In order for your extension's JavaScript to be loaded into the frontend, we need to tell Flarum where to find it. We can do this using the `Frontend` extender's `js` method. Add it to your extension's `extend.php` file: + +```php +js(__DIR__.'/js/dist/forum.js') +]; +``` + +Flarum will make anything you `export` from `forum.js` available in the global `flarum.extensions['acme-hello-world']` object. Thus, you may choose to expose your own public API for other extensions to interact with. + +:::tip External Libraries + +Only one main JavaScript file per extension is permitted. If you need to include any external JavaScript libraries, either install them with NPM and `import` them so they are compiled into your JavaScript file, or see [Routes and Content](/extend/routes.md) to learn how to add extra `'; + }) +]; +``` + +You can also add content onto your frontend route registrations: + +```php +return [ + (new Extend\Frontend('forum')) + ->route('/users', 'acme.users', function (Document $document, Request $request) { + $document->title = 'Users'; + }) +]; +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/search.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/search.md new file mode 100644 index 000000000..9da3f70b3 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/search.md @@ -0,0 +1,202 @@ +# 搜索 + +Flarum treats searching and filtering as parallel but distinct processes. Which process is used to handle a request to a [`List` API endpoint](/extend/api.md#api-endpoints) depends on the query parameters: + +- Filtering is applied when the `filter[q]` query param is omitted. Filters represent **structured** queries: for instance, you might want to only retrieve discussions in a certain category, or users who registered before a certain date. Filtering computes results based entirely on `filter[KEY] = VALUE` query parameters. +- Searching is applied when the `filter[q]` query param is included. Searches represent **unstructured** queries: the user submits an arbitrary string, and data records that "match" it are returned. For instance, you might want to search discussions based on the content of their posts, or users based on their username. Searching computes results based solely on parsing the `filter[q]` query param: all other `filter[KEY] = VALUE` params are ignored when searching. It's important to note that searches aren't entirely unstructured: the dataset being searched can be constrained by gambits (which are very similar to filters, and will be explained later). + +This distinction is important because searches and filters have very different use cases: filters represent *browsing*: that is, the user is passively looking through some category of content. In contrast, searches represent, well, *searching*: the user is actively looking for content based on some criteria. + +Flarum implements searching and filtering via per-model `Searcher` and `Filterer` classes (discussed in more detail below). Both classes accept a [`Flarum\Query\QueryCriteria`](https://api.docs.flarum.org/php/master/flarum/query/querycriteria) instance (a wrapper around the user and query params), and return a [`Flarum\Query\QueryResults`](https://api.docs.flarum.org/php/master/flarum/query/queryresults) instance (a wrapper around an Eloquent model collection). This common interface means that adding search/filter support to models is quite easy. + +One key advantage of this split is that it allows searching to be implemented via an external service, such as ElasticSearch. For larger communities, this can be significantly more performant and accurate. There isn't a dedicated extender for this yet, so for now, replacing the default Flarum search driver requires overriding the container bindings of `Searcher` classes. This is a highly advanced use case; if you're interested in doing this, please reach out on our [community forums](https://discuss.flarum.org/). + +Remember that the [JSON:API schema](https://jsonapi.org/format) is used for all API requests. + +:::tip Reuse Code + +Often, you might want to use the same class as both a `Filter` and a `Gambit` (both explained below). Your classes can implement both interface; see Flarum core's [`UnreadFilterGambit`](https://github.com/flarum/framework/blob/main/framework/core/src/Discussion/Query/UnreadFilterGambit.php) for an example. + +::: + +:::tip Query Builder vs Eloquent Builder + +`Filter`s, `Gambit`s, filter mutators, and gambit mutators (all explained below) receive a "state" parameter, which wraps + +::: + +## Filtering + +Filtering constrains queries based on `Filters` (highlighted in code to avoid confusion with the process of filtering), which are classes that implement `Flarum\Filter\FilterInterface` and run depending on query parameters. After filtering is complete, a set of callbacks called "filter mutators" run for every filter request. + +When the `filter` method on a `Filterer` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Filter/AbstractFilterer.php#L50-L93)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Filterer` class's `getQuery()` method. +2. We loop through all `filter[KEY] = VALUE` query params. For each of these, any `Filter`s registered to the model whose `getFilterKey()` method matches the query param `KEY` is applied. `Filter`s can be negated by providing the query param as `filter[-KEY] = VALUE`. Whether or not a `Filter` is negated is passed to it as an argument: implementing negation is up to the `Filter`s. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "filter mutators" are applied. These are callbacks that receive the filter state (a wrapper around the query builder and current user) and filter criteria, and perform some arbitrary changes. All "filter mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Filtering for an Existing Model + +Let's say you've added a `country` column to the User model, and would like to filter users by country. We'll need to define a custom `Filter`: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +Note that `FilterState` is a wrapper around the Eloquent builder's underlying Query builder and the current user. + +Also, let's pretend that for some reason, we want to omit any users that have a different country from the current user on ANY filter. We can use a "filter mutator" for this: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +Now, all we need to do is register these via the Filter extender: + +```php + // Other extenders + (new Extend\Filter(UserFilterer::class)) + ->addFilter(CountryFilter::class) + ->addFilterMutator(OnlySameCountryFilterMutator::class), + // Other extenders +``` + +### Add Filtering to a New Model + +To filter a model that doesn't support filtering, you'll need to create a subclass of `Flarum/Filter/AbstractFilterer` for that model. For an example, see core's [UserFilterer](https://github.com/flarum/framework/blob/main/framework/core/src/User/Filter/UserFilterer.php). + +Then, you'll need to use that filterer in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +## Searching + +Searching constrains queries by applying `Gambit`s, which are classes that implement `Flarum\Search\GambitInterface`, based on the `filter[q]` query param. After searching is complete, a set of callbacks called "search mutators" run for every search request. + +When the `search` method on a `Searcher` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Search/AbstractSearcher.php#L55-L79)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Searcher` class's `getQuery()` method. +2. The `filter[q]` param is split by spaces into "tokens". Each token is matched against the model's registered `Gambit`s (each gambit has a `match` method). For any tokens that match a gambit, that gambit is applied, and the token is removed from the query string. Once all regular `Gambit`s have ran, all remaining unmatched tokens are passed to the model's `FullTextGambit`, which implements the actual searching logic. For example if searching discussions, in the `filter[q]` string `'author:1 hello is:hidden' world`, `author:1` and `is:hidden` would get matched by core's Author and Hidden gambits, and `'hello world'` (the remaining tokens) would be passed to the `DiscussionFulltextGambit`. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "search mutators" are applied. These are callbacks that receive the search state (a wrapper around the query builder and current user) and criteria, and perform some arbitrary changes. All "search mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Searching for an Existing Model + +Let's reuse the "country" examples we used above, and see how we'd implement the same things for searching: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +:::warning No Spaces in Gambit Patterns! + +Flarum splits the `filter[q]` string into tokens by splitting it at spaces. This means that your custom gambits can NOT use spaces as part of their pattern. + +::: + +:::tip AbstractRegexGambit + +All a gambit needs to do is implement `Flarum\Search\GambitInterface`, which receives the search state and a token. It should return if this gambit applies for the given token, and if so, make whatever mutations are necessary to the query builder accessible as `$searchState->getQuery()`. + +However, for most gambits, the `AbstractRegexGambit` abstract class (used above) should be used as a base class. This makes it a lot simpler to match and apply gambits. + +::: + +Similarly, the search mutator we need is almost identical to the filter mutator from before: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +We can register these via the `SimpleFlarumSearch` extender (in the future, the `Search` extender will be used for registering custom search drivers): + +```php + // Other extenders + (new Extend\SimpleFlarumSearch(UserSearcher::class)) + ->addGambit(CountryGambit::class) + ->addSearchMutator(OnlySameCountrySearchMutator::class), + // Other extenders +``` + +### Add Searching to a New Model + +To support searching for a model, you'll need to create a subclass of `Flarum/Search/AbstractSearcher` for that model. For an example, see core's [UserSearcher](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/UserSearcher.php). + +Then, you'll need to use that searcher in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +Every searcher **must** have a fulltext gambit (the logic that actually does the searching). Otherwise, it won't be booted by Flarum, and you'll get an error. See core's [FulltextGambit for users](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/Gambit/FulltextGambit.php) for an example. You can set (or override) the full text gambit for a searcher via the `SimpleFlarumSearch` extender's `setFullTextGambit()` method. + +### Search Drivers + +Coming soon! + +## Frontend Tools + +Coming soon! diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md new file mode 100644 index 000000000..07e3e4d91 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/service-provider.md @@ -0,0 +1,65 @@ +# Service Provider + +As noted throughout this documentation, Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection. [Service Providers](https://laravel.com/docs/8.x/providers) allow low-level configuration and modification of the Flarum backend. The most common use case for service providers is to create, modify, or replace container bindings. That being said, service providers allow you full access to run whatever logic you need during application boot with access to the container. + +:::caution Advanced Use Only!!! + +Unlike with other extenders, the Service Provider layer is NOT use-case driven, and is NOT considered public API. It is subject to change at any time, without notice or deprecation. This should only be used if you know what you're doing, and the other extenders don't satisfy your use case. + +::: + +## Flarum Boot Process + +To understand service providers, you must first understand the order in which Flarum boots. Most of this happens in [Flarum\Foundation\InstalledSite](https://github.com/flarum/framework/blob/main/framework/core/src/Foundation/InstalledSite.php) + +1. The container and application are initialized, and essential bindings (config, environment, logger) are registered +2. The `register` methods of all core service providers are run. +3. The `extend` methods of all extenders used by all enabled extensions are run. +4. The `extend` methods of all extenders used in the Flarum site's local `extend.php` are run. +5. The `boot` methods of all core service providers are run. + +## Custom Service Providers + +A custom service provider should extend `Flarum\Foundation\AbstractServiceProvider`, and can have a `boot` and a `register` method. For example: + +```php +container->resolving(SomeClass::class, function ($container) { + return new SomeClass($container->make('some.binding')); + }); + } + + public function boot(Container $container) + { + // custom logic here + } +} +``` + +The `register` method will run during step (3) above, and the `boot` method will run during step (5) above. In the `register` method, the container is available via `$this->container`. In the `boot` method, the container (or any other arguments), should be injected via typehinted method arguments. + +Flarum does not currently support Laravel Octane, but some [best practices](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane), like using the `$container` argument inside `bind`, `singleton`, and `resolving` callbacks instead of `$this->container` should be used. See the [Octane documentation](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane) for more information. + +To actually register your custom service provider, you can use the `ServiceProvider` extender in `extend.php`: + +```php +register(CustomServiceProvider::class), + // Other extenders +]; +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/settings.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/settings.md new file mode 100644 index 000000000..ffefdcde5 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/settings.md @@ -0,0 +1,90 @@ +# Settings + +At some point while making an extension, you might want to read some of the forum's settings or store certain settings specific to your extension. Thankfully, Flarum makes this very easy. + +## The Settings Repository + +Reading or changing settings can be done using an implementation of the `SettingsRepositoryInterface`. Because Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection, you don't need to worry about where to obtain such a repository, or how to instantiate one. Instead, you can rely on the container to instantiate your class and inject the correct dependencies. + +```php +settings = $settings; + } +} +``` + +Great! Now the `SettingsRepositoryInterface` is available through `$this->settings` to our class. + +### Reading Settings + +To read settings, all we have to do is use the repository's `get()` function: + +`$this->settings->get('forum_title')` + +The `get()` function accepts two arguments: + +1. The name of the setting you are trying to read. +2. (Optional) A default value if no value has been stored for such a setting. By default, this will be `null`. + +### Storing Settings + +Storing settings ist just as easy, use the `set()` function: + +`$this->settings->set('forum_title', 'Super Awesome Forum')` + +The `set` function also accepts two arguments: + +1. The name of the setting you are trying to change. +2. The value you want to store for this setting. + +### Other Functions + +The `all()` function returns an array of all known settings. + +The `delete($name)` function lets you remove a named setting. + +## Settings in the Frontend + +### Editing Settings + +To learn more about adding settings through the admin dashboard, see the [relevant documentation](admin.md). +### Accessing Settings + +All settings are available in the `admin` frontend via the `app.data.settings` global. However, this is not done in the `forum` frontend, as anyone can access it, and you wouldn't want to leak all your settings! (Seriously, that could be a very problematic data breach). + +Instead, if we want to use settings in the `forum` frontend, we'll need to serialize them and send them alongside the initial forum data payload. + +This can be done via the `Settings` extender. For example: + +**extend.php** + +```php +use Flarum\Extend; + +return [ + (new Extend\Settings) + ->serializeToForum('myCoolSetting', 'my.cool.setting.key') + ->serializeToForum('myCoolSettingModified', 'my.cool.setting.key', function ($retrievedValue) { + // This third argument is optional, and allows us to pass the retrieved setting through some custom logic. + // In this example, we'll append a string to it. + + return "My Cool Setting: $retrievedValue"; + }, "default value!"), +] +``` + +Now, the `my.cool.setting.key` setting will be accessible in the frontend as `app.forum.attribute("myCoolSetting")`, and our modified value will be accessible via `app.forum.attribute("myCoolSettingModified")`. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md new file mode 100644 index 000000000..3dc39416b --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/slugging.md @@ -0,0 +1 @@ +# Model Slugging diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/start.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/start.md new file mode 100644 index 000000000..ade6691da --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/start.md @@ -0,0 +1,153 @@ +# 开始 + +想打造一个 Flarum 扩展? 来对地方了! 本文档将带您了解一些基本概念,之后您将从头开始打造您的第一个 Flarum 扩展。 + +## 架构 + +为了理解如何扩展 Flarum,我们需要先明白 Flarum 是如何构建的。 + +要知道,Flarum 使用了一些 _现代_ 语言和工具。 如果您以前只构建过 WordPress 的插件,您可能会觉得有点力不从心。 没有关系 —— 这是一个学习新事物和扩展技能的好机会。 不过我们建议您在开始之前先熟悉一下下面描述的技术。 + +Flarum 的构成有三层: + +* 第一层,**后端**。 后端用 [面向对象的 PHP 语言](https://laracasts.com/series/object-oriented-bootcamp-in-php)编写,并通过 [Composer](https://getcomposer.org/) 使用了大量的 [Laravel](https://laravel.com/) 组件和其他资源包。 您还需要熟悉 [依赖项注入](https://laravel.com/docs/6.x/container) 的概念,它在整个后端中都有使用。 + +* 第二层,后端开放的一个 **公共 API**,允许前端客户端与论坛数据进行交互。 该接口根据 [JSON:API 规范](https://jsonapi.org/) 构建。 + +* 第三层,默认的 Web 界面,俗称 **前端**。 这是一个使用 API 的 [单页应用](https://en.wikipedia.org/wiki/Single-page_application), 由一个简单的类 React 框架 [Mithril.js](https://mithril.js.org/) 构建。 + +扩展程序通常需要与这三层都进行交互才能有所为。 例如,如果您想创建一个可以在用户资料中添加新属性的扩展,则需要在 **后端** 中添加相应的数据库结构,通过 **公共 API** 调用该数据,然后在 **前端** 显示这个数据并允许用户修改它。 + +那…… 如何扩展这些层呢? + +## 扩展器 + +为了扩展 Flarum,我们需要用到 **扩展器**,让我们先了解一下它的概念。 扩展器其实就是 *声明性* 对象,您可以通过简单的方式描述想要实现的内容(比如向论坛添加新的路由,或者在创建新主题帖时执行某些代码)。 + +每个扩展器都是不同的, 但是大体上长这样: + +```php +// 注册要交付给前端的 JavaScript 和 CSS 文件 +(new Extend\Frontend('forum')) + ->js(__DIR__.'/forum-scripts.js') + ->css(__DIR__.'/forum-styles.css') +``` + +您首先创建一个扩展器实例,然后调用方法以对其进行进一步配置。 所有方法都将返回结果到该扩展器本身,因此您只需要通过链式方法调用就可以实现您的整个配置。 + +为了保持一致,我们在后端(PHP)和前端(JavaScript)都使用了扩展器的概念。 您在扩展中做的 _每一件事_ 都应当通过扩展器来完成,因为扩展器是我们给予您的 **保证** —— 保证 Flarum 小版本更新绝对不破坏您的扩展。 + +所有 Flarum 核心提供的可用扩展器都可以在 [`Extend` 命名空间](https://github.com/flarum/framework/blob/main/framework/core/src/Extend)[(PHP API 文档)](https://api.docs.flarum.org/php/master/flarum/extend)中找到。扩展程序亦有可能提供他们[自有的扩展器](extensibility.md#custom-extenders)。 + +## 世界你好 + +想亲眼看看一个扩展器的执行? Flarum 安装根目录中的 `extend.php` 是为您的站点注册扩展器的最简单的途径,它应该会返回一个扩展器对象的数组。 它应该会返回一个扩展器对象的数组。 打开该文件并添加以下内容: + +```php +content(function (Document $document) { + $document->head[] = ''; + }) +]; +``` + +现在,访问您的论坛,接受真挚的问候(尽管很突兀)。 👋 + +对于简单的网站定制,比如添加一些自定义的 CSS 或 JavaScript,或者整合您网站的认证系统,论坛根目录下的 `extend.php` 文件是非常好用的。 但是在某些时候,您的自定义可能会超出它的限制范围。 或者您想建立一个扩展程序,并分享到社区。 那么是时候建立一个扩展程序了! + +## 打包扩展程序 + +[Composer](https://getcomposer.org) 是 PHP 的一个依赖管理工具。 它允许应用程序轻松地拉取外部代码库,并保持他们是最新的,以便及时应用安全补丁和错误修复。 + +如上所述,每个 Flarum 扩展程序也是一个 Composer 包。 这意味着一个人可以「require」某个扩展程序,Composer 会把它拉取给 Flarum,同时使扩展程序保持最新版本。 Nice! + +在开发过程中,您可以在本地处理您的扩展程序,并建立一个 [Composer 本地路径仓库](https://getcomposer.org/doc/05-repositories.md#path) 以安装您的本地副本。 在 Flarum 安装根目录下创建一个新的 `packages` 文件夹,然后运行这个命令来告诉 Composer 它可以在这里找到软件包: + +```bash +composer config repositories.0 path "packages/*" +``` + +现在,来构建我们的第一个扩展程序吧。 在 `packages` 里面为您的扩展程序建立一个新的文件夹,命名为 `hello-world`。 我们会在里面放两个文件:`extend.php` 和 `composer.json`。 这些文件是扩展程序的心脏和灵魂。 + +### extend.php + +扩展程序的 `extend.php` 跟您站点根目录下的那个是一模一样的。 它会返回一个扩展器对象数组,并告诉 Flarum 您想要做什么。 现在,将前面我们操作的 `Frontend` 扩展器移动到这里。 + +### composer.json + +我们需要告诉 Composer 一些您的软件包的信息,创建 `composer.json` 文件已写入这些信息: + +```json +{ + "name": "acme/flarum-hello-world", + "description": "向世界问好!", + "type": "flarum-extension", + "require": { + "flarum/core": ">=0.1.0-beta.16 <=0.1.0" + }, + "autoload": { + "psr-4": {"Acme\\HelloWorld\\": "src/"} + }, + "extra": { + "flarum-extension": { + "title": "Hello World", + "icon": { + "name": "fas fa-smile", + "backgroundColor": "#238c59", + "color": "#fff" + } + } + } +} +``` + +* **name**,名字。 是 Composer 软件包的名字。 格式是 `供应商/包名`。 + * 您需要起一个全世界独一无二的供应商名,或者可以直接沿用 GitHub 的用户名。 以本教程为例,这里我们假设 `acme` 是您的供应商名。 + * 您应该给包 `包名` 加上 `flarum-` 前缀,以指明此包是专门给 Flarum 用的。 + +* **description**,描述。 用一句话描述这个扩展程序的作用是什么。 + +* **type**,类型。 只能是 `flarum-extension`。 这确保了当别人「require」您的扩展程序时,能被正确识别。 + +* **require**,依赖。 描述您的扩展程序自身的依赖关系。 + * 您需要在这里指定您的扩展程序所兼容的 Flarum 版本。 + * 这里也是列出您的代码需要使用的 Composer 外部工具库的地方。 + +* **autoload**,定义一个从命名空间到目录的映射,告诉 Composer 在哪里可以找到扩展程序的类。 此处的命名空间应以 驼峰写法 反映扩展程序的供应商和包名. + +* **extra.flarum-extension**,包含一些 Flarum 特有的信息,比如您扩展程序在论坛的显示名称以及图标。 + * **title** 您的扩展程序的显示名称。 + * **icon** 是一个定义您扩展程序图标的对象。 **name** 属性是 [Font Awesome 图标名](https://fontawesome.com/icons)。 剩下的都被用作图标的 `style` 属性。 + +请参阅 [composer.json 模式](https://getcomposer.org/doc/04-schema.md) 文档,以获取有关可以添加到 `composer.json` 中的其他属性的信息。 + +:::info [Flarum CLI](https://github.com/flarum/cli) + +使用 [FoF 扩展生成器](https://github.com/FriendsOfFlarum/extension-generator) 自动创建扩展程序的基架。 +```bash +$ flarum-cli init +``` + +::: + +### 安装您的扩展 + +最后一步就是安装您的扩展。 进入 Flarum 安装根目录,执行以下命令: + +```bash +composer require acme/flarum-hello-world *@dev +``` + +执行完成后,前往您论坛后台管理面板启用插件,最后回到您的论坛。 + +*啾,咻,铮铛* + +哇! 你好,扩展! + +很好,我们取得了一些进展。 我们学习了如何设置扩展和使用扩展,打开了新世界的大门。 继续阅读以了解如何扩展 Flarum 的前端。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md new file mode 100644 index 000000000..28e6c4aa7 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/static-code-analysis.md @@ -0,0 +1,86 @@ +# Static Code Analysis + +Static code analysis is the process of analyzing the source code against a set of rules to find bugs, code smells, and security vulnerabilities. This is a great way to improve the quality of your code and to find potential issues before they are deployed to production. An example is validating the typings of a function to ensure that the function is called with the correct arguments. + +Flarum provides a static code analysis package based on [PHPStan](https://phpstan.org/) that can be added to your extension. In this guide, we will show you how to add the package to your extension and how to run the analysis. + +## Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update the infrastructure for phpstan to your code: + +```bash +$ flarum-cli infra phpstan +``` + +::: + +First you need to require the `flarum/phpstan` package in your extension. You can do this by running the following command in the root of our extension: + +```bash +composer require --dev flarum/phpstan:^1.0 +``` + +Next, you need to create a `phpstan.neon` file in the root of your extension. This file contains [the configuration for PHPStan](https://phpstan.org/config-reference). You can copy the following configuration into the file: + +```neon +includes: + - vendor/flarum/phpstan/extension.neon + +parameters: + # The level will be increased in Flarum 2.0 + level: 5 + paths: + - src + - extend.php + excludePaths: + - *.blade.php + checkMissingIterableValueType: false + databaseMigrationsPath: ['migrations'] +``` + +Finally, you need to add the following script to your `composer.json` file: + +```json +{ + "scripts": { + "analyse:phpstan": "phpstan analyse", + "clear-cache:phpstan": "phpstan clear-result-cache" + }, + "scripts-descriptions": { + "analyse:phpstan": "Run static analysis" + } +} +``` + +## Running the analysis + +To run the analysis, you can run the following command in the root of your extension: + +```bash +composer analyse:phpstan +``` + +If you want to clear the cache before running the analysis, you can run the following command: + +```bash +composer clear-cache:phpstan && composer analyse:phpstan +``` + +## GitHub Actions + +You can also run the analysis using GitHub Actions. Checkout the page on [GitHub Actions](github-actions.md) for more information. + +## Tips + +### Extended model attribute types + +PHPStan needs to be able to determine the type of an attribute added to an existing model. To do this you can use the `Extend\Model(...)->cast(...)` method. + +For example, if your extension were to add a `is_cool` attribute to the `User` model, you can use [attribute casting](https://laravel.com/docs/8.x/eloquent-mutators#attribute-casting) to explicitly define the attribute as boolean. The `flarum/phpstan` package will automatically detect this and communicate it to PHPStan. + +```php +(new Extend\Model(User::class)) + ->cast('is_cool', 'bool'), +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/testing.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/testing.md new file mode 100644 index 000000000..b1342ede0 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/testing.md @@ -0,0 +1,565 @@ +# 测试 + +Automated testing ensures that your extension performs as you expect it to, helps avoid introducing new bugs or regressions, and saves time on manual testing. Flarum currently provides tooling for automated backend unit and integration tests, and we plan to release support for frontend unit testing and E2E testing in the future. + +## Backend Tests + +The `flarum/testing` library is used by core and some bundled extensions for automated unit and integration tests. It is essentially a collection of utils that allow testing Flarum core and extensions with PHPUnit. + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update backend testing infrastructure to your code: + +```bash +$ flarum-cli infra backendTesting +``` + +::: + +```bash +composer require --dev flarum/testing:^1.0 +``` + +Then, you will need to set up a file structure for tests, and add PHPUnit configuration: + +``` +tests +├── fixtures (put any files needed by your tests here (blade templates, images, etc)) +├── integration +│ ├── setup.php (code below) +│ └── PUT INTEGRATION TESTS HERE (organizing into folder is generally a good idea) +├── unit +│ ├── PUT UNIT TESTS HERE +├── phpunit.integration.xml (code below) +└── phpunit.unit.xml (code below) +``` + +#### phpunit.integration.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for integration tests. You can tweak this as needed, but keep `backupGlobals`, `backupStaticAttributes`, and `processIsolation` unchanged. + +```xml + + + + + + + ./integration + + + +``` + +#### phpunit.unit.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for unit tests. You can tweak this as needed. + +```xml + + + + + + + ./unit + + + + + + +``` + +#### setup.php + +This script will be run to set up a testing database / file structure. + +```php +run(); +``` + +#### composer.json Modifications + +We will also want to add scripts to our `composer.json`, so that we can run our test suite via `composer test`. Add some variant of the following to your `composer.json`: + +```json +"scripts": { + "test": [ + "@test:unit", + "@test:integration" + ], + "test:unit": "phpunit -c tests/phpunit.unit.xml", + "test:integration": "phpunit -c tests/phpunit.integration.xml", + "test:setup": "@php tests/integration/setup.php" +}, +"scripts-descriptions": { + "test": "Runs all tests.", + "test:unit": "Runs all unit tests.", + "test:integration": "Runs all integration tests.", + "test:setup": "Sets up a database for use with integration tests. Execute this only once." +} +``` + +#### GitHub Testing Workflow + +To run tests on every commit and pull request, check out the [GitHub Actions](github-actions.md) page. + +--- + +Now that we have everything in place, we need to set up our testing site for integration tests. For this, we will need a MySQL or MariaDb instance, and a place to store testing files. + +Testing database information is configured via the `DB_HOST` (defaults to `localhost`), `DB_PORT` (defaults to `3306`), `DB_DATABASE` (defaults to `flarum_test`), `DB_USERNAME` (defaults to `root`), `DB_PASSWORD` (defaults to `root`), and `DB_PREFIX` (defaults to `''`) environmental variables. The testing tmp directory path is configured via the `FLARUM_TEST_TMP_DIR_LOCAL` or `FLARUM_TEST_TMP_DIR` environmental variables, with the former taking precedence over the latter. If neither are provided, a `tmp` directory will be created in the `vendor` folder of your extension's local install. + +Now that we've provided the needed information, all we need to do is run `composer test:setup` in our extension's root directory, and we have our testing environment ready to go! + +Since [(almost)](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/tests/integration/api/discussions/ListWithFulltextSearchTest.php#L29-L45) all database operations in integration tests are run in transactions, developers working on multiple extensions will generally find it more convenient to use one shared database and tmp directory for testing all their extensions. To do this, set the database config and `FLARUM_TEST_TMP_DIR` environmental variables in your `.bashrc` or `.bash_profile` to the path you want to use, and run the setup script for any one extension (you'll still want to include the setup file in every repo for CI testing via GitHub Actions). You should then be good to go for any Flarum extension (or core). + +### Using Integration Tests + +Flarum's integration test utils are contained in the `Flarum\Testing\integration\TestCase` class. It: + +- Boots (and makes available) an instance of the Flarum application. +- Allows pre-populating the database, enabling extensions, and adding extenders. +- Runs all database changes in transactions, so your test database retains the default post-installation state. +- Allows sending requests through the middleware stack to test HTTP endpoints. + +Your testcase classes should extend this class. + +#### Test Case Setup + +There are several important utilities available for your test cases: + +- The `setting($key, $value)` method allows you to override settings before the app has booted. This is useful if your boot process has logic depending on settings (e.g. which driver to use for some system). +- Similarly, the `config($key, $value)` method allows you to override config.php values before the app has booted. You can use dot-delimited keys to set deep-nested values in the config array. +- The `extension($extensionId)` method will take Flarum IDs of extensions to enable as arguments. Your extension should always call this with your extension's ID at the start of test cases, unless the goal of the test case in question is to confirm some behavior present without your extension, and compare that to behavior when your extension is enabled. If your extension is dependent on other extensions, make sure they are included in the composer.json `require` field (or `require-dev` for [optional dependencies](extending-extensions.md)), and also list their composer package names when calling `extension()`. Note that you must list them in a valid order. +- The `extend($extender)` method takes instances of extenders as arguments, and is useful for testing extenders introduced by your extension for other extensions to use. +- The `prepareDatabase()` method allow you to pre-populate your database. This could include adding users, discussions, posts, configuring permissions, etc. Its argument is an associative array that maps table names to arrays of [record arrays](https://laravel.com/docs/8.x/queries#insert-statements). + +If your test case needs users beyond the default admin user, you can use the `$this->normalUser()` method of the `Flarum\Testing\integration\RetrievesAuthorizedUsers` trait. + +:::warning + +The `TestCase` class will boot a Flarum instance the first time its `app()` method is called. Any uses of `prepareDatabase`, `extend`, or `extension` after this happens will have no effect. Make sure you have done all the setup you need in your test case before calling `app()`, or `database()`, `server()`, or `send()`, which call `app()` implicitly. If you need to make database modifications after the app has booted, you can use the regular Eloquent save method, or the `Illuminate\Database\ConnectionInterface` instance obtained via calling the `database()` method. + +::: + +Of course, since this is all based on PHPUnit, you can use the `setUp()` methods of your test classes for common setup tasks. + +For example: + +```php +setting('my.custom.setting', true); + + // Let's assume our extension depends on tags. + // Note that tags will need to be in your extension's composer.json's `require-dev`. + // Also, make sure you include the ID of the extension currently being tested, unless you're + // testing the baseline without your extension. + $this->extension('flarum-tags', 'my-cool-extension'); + + // Note that this input isn't validated: make sure you're populating with valid, representative data. + $this->prepareDatabase([ + 'users' => [ + $this->normalUser() // Available for convenience. + ], + 'discussions' => [ + ['id' => 1, 'title' => 'some title', 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 1, 'first_post_id' => 1, 'comment_count' => 1] + ], + 'posts' => [ + ['id' => 1, 'number' => 1, 'discussion_id' => 1, 'created_at' => Carbon::now(), 'user_id' => 1, 'type' => 'comment', 'content' => '

something

'] + ] + ]); + + // Most test cases won't need to test extenders, but if you want to, you can. + $this->extend((new CoolExtensionExtender)->doSomething('hello world')); + } + + /** + * @test + */ + public function some_phpunit_test_case() + { + // ... + } + + // ... +} +``` + +#### Sending Requests + +A common application of automated testing is pinging various HTTP endpoints with various data, authenticated as different users. You can use this to ensure that: + +- Users can't access content they're not supported to access. +- Permission-based create/edit/delete operations perform as expected. +- The type and schema of data returned is correct. +- Some desired side effect is applied when pinging an API. +- The basic API operations needed by your extension aren't erroring, and don't break when you make changes. + +`TestCase` provides several utilities: + +- The `request()` method constructs a `Psr\Http\Message\ServerRequestInterface` implementing object from a path, a method, and some options, which can be used for authentication, attaching cookies, or configuring the JSON request body. See the [method docblock](https://github.com/flarum/testing/blob/main/src/integration/TestCase.php) for more information on available options. +- Once you've created a request instance, you can send it (and get a response object back) via the `send()` method. + +For example: + +```php +send( + $this->request('GET', '/api/users', ['authenticatedAs' => 1]) + ->withQueryParams(['filter' => ['q' => 'john group:1'], 'sort' => 'username']) + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + /** + * @test + */ + public function can_create_user() + { + $response = $this->send( + $this->request( + 'POST', + '/api/users', + [ + 'authenticatedAs' => 1, + 'json' => [ + 'data' => [ + 'attributes' => [ + 'username' => 'test', + 'password' => 'too-obscure', + 'email' => 'test@machine.local' + ] + ] + ] + ] + ) + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + // ... +} +``` + +:::caution + +If you want to send query parameters in a GET request, you can't include them in the path; you'll need to add them afterwards with the `withQueryParams` method. + +::: + +:::caution + +This is an extreme edge case, but note that MySQL does not update the fulltext index in transactions, so the standard approach won't work if you're trying to test a modified fulltext query. See [core's approach](https://github.com/flarum/framework/blob/main/framework/core/tests/integration/extenders/SimpleFlarumSearchTest.php) for an example of a workaround. + +::: + +#### Console Tests + +If you want to test custom console commands, you can extend `Flarum\Testing\integration\ConsoleTestCase` (which itself extends the regular `Flarum\Testing\integration\TestCase`). It provides 2 useful methods: + +- `$this->console()` returns an instance of `Symfony\Component\Console\Application` +- `$this->runCommand()` takes an array that will be wrapped in `Symfony\Component\Console\Input\ArrayInput`, and run. See the [Symfony code docblock](https://github.com/symfony/console/blob/5.x/Input/ArrayInput.php#L22) for more information. + +For example: + +```php + 'some:command', // The command name, equivalent of `php flarum some:command` + 'foo' => 'bar', // arguments + '--lorem' => 'ipsum' // options + ]; + + $this->assertEquals('Some Output.', $this->runCommand($input)); + } +} +``` + +### Using Unit Tests + +Unit testing in Flarum uses [PHPUnit](https://phpunit.de/getting-started/phpunit-9.html) and so unit testing in flarum is much like any other PHP application. You can find [general tutorials on testing](https://www.youtube.com/watch?v=9-X_b_fxmRM) if you're also new to php. + +When writing unit tests in Flarum, here are some helpful tips. + +#### Mocking Flarum Services + +Unlike the running app, or even integration tests, there is no app/container/etc to inject service instances into our classes. Now all the useful settings, or helpers your extension use require a _mock_ . We want to limit mocking to just the key services, supporting only the minimum interactions needed to test the contract of our individual functions. + +```php + public function setUp(): void + { + parent::setUp(); + // example - if our setting needs settings, we can mock the settings repository + $settingsRepo = m::mock(SettingsRepositoryInterface::class); + // and then control specific return values for each setting key + $settingsRepo->shouldReceive('get')->with('some-plugin-key')->andReturn('some-value-useful-for-testing'); + // construct your class under test, passing mocked services as needed + $this->serializer = new YourClassUnderTest($settingsRepo); + } +``` + +Some aspects require more mocks. If you're validating authorization interactions for instance you might need to mock your users `User::class` and the request's method that provides them as well! + +``` + $this->actor = m::mock(User::class); + $request = m::mock(Request::class)->makePartial(); + $request->shouldReceive('getAttribute->getActor')->andReturn($this->actor); + $this->actor->shouldReceive('SOME PERMISSION')->andReturn(true/false); +``` + +NOTE: If you find your extension needs _lots and lots_ of mocks, or mocks that feel unrelated, it might be an opportunity to simplify your code, perhaps moving key logic into their own smaller functions (that dont require mocks). + +## Frontend Tests + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update frontend testing infrastructure to your code: + +```bash +$ flarum-cli infra frontendTesting +``` + +::: + +First, you need to install the Jest config dev dependency: + +```bash +$ yarn add --dev @flarum/jest-config +``` + +Then, add the following to your `package.json`: + +```json +{ + "type": "module", + "scripts": { + ..., + "test": "yarn node --experimental-vm-modules $(yarn bin jest)" + } +} +``` + +Rename `webpack.config.js` to `webpack.config.cjs`. This is necessary because Jest doesn't support ESM yet. + +Create a `jest.config.cjs` file in the root of your extension: + +```js +module.exports = require('@flarum/jest-config')(); +``` + +If you are using TypeScript, create tsconfig.test.json with the following content: + +```json +{ + "extends": "./tsconfig.json", + "include": ["tests/**/*"], + "files": ["../../../node_modules/@flarum/jest-config/shims.d.ts"] +} +``` + +Then, you will need to set up a file structure for tests: + +``` +js +├── dist +├── src +├── tests +│ ├── unit +│ │ └── functionTest.test.js +│ ├── integration +│ │ └── componentTest.test.js +├── package.json +├── tsconfig.json +├── tsconfig.test.json +├── jest.config.cjs +└── webpack.config.cjs +``` + +#### GitHub Testing Workflow + +To run tests on every commit and pull request, check out the [GitHub Actions](github-actions.md) page. + +### Using Unit Tests + +Like any other JS project, you can use Jest to write unit tests for your frontend code. Checkout the [Jest docs](https://jestjs.io/docs/using-matchers) for more information on how to write tests. + +Here's a simple example of a unit test fo core's `abbreviateNumber` function: + +```ts +import abbreviateNumber from '../../../../src/common/utils/abbreviateNumber'; + +test('does not change small numbers', () => { + expect(abbreviateNumber(1)).toBe('1'); +}); + +test('abbreviates large numbers', () => { + expect(abbreviateNumber(1000000)).toBe('1M'); + expect(abbreviateNumber(100500)).toBe('100.5K'); +}); + +test('abbreviates large numbers with decimal places', () => { + expect(abbreviateNumber(100500)).toBe('100.5K'); + expect(abbreviateNumber(13234)).toBe('13.2K'); +}); +``` + +### Using Integration Tests + +Integration tests are used to test the components of your frontend code and the interaction between different components. For example, you might test that a page component renders the correct content based on certain parameters. + +Here's a simple example of an integration test for core's `Alert` component: + +```ts +import Alert from '../../../../src/common/components/Alert'; +import m from 'mithril'; +import mq from 'mithril-query'; +import { jest } from '@jest/globals'; + +describe('Alert displays as expected', () => { + it('should display alert messages with an icon', () => { + const alert = mq(m(Alert, { type: 'error' }, 'Shoot!')); + expect(alert).toContainRaw('Shoot!'); + expect(alert).toHaveElement('i.icon'); + }); + + it('should display alert messages with a custom icon when using a title', () => { + const alert = mq(Alert, { type: 'error', icon: 'fas fa-users', title: 'Woops..' }); + expect(alert).toContainRaw('Woops..'); + expect(alert).toHaveElement('i.fas.fa-users'); + }); + + it('should display alert messages with a title', () => { + const alert = mq(m(Alert, { type: 'error', title: 'Error Title' }, 'Shoot!')); + expect(alert).toContainRaw('Shoot!'); + expect(alert).toContainRaw('Error Title'); + expect(alert).toHaveElement('.Alert-title'); + }); + + it('should display alert messages with custom controls', () => { + const alert = mq(Alert, { type: 'error', controls: [m('button', { className: 'Button--test' }, 'Click me!')] }); + expect(alert).toHaveElement('button.Button--test'); + }); +}); + +describe('Alert is dismissible', () => { + it('should show dismiss button', function () { + const alert = mq(m(Alert, { dismissible: true }, 'Shoot!')); + expect(alert).toHaveElement('button.Alert-dismiss'); + }); + + it('should call ondismiss when dismiss button is clicked', function () { + const ondismiss = jest.fn(); + const alert = mq(Alert, { dismissible: true, ondismiss }); + alert.click('.Alert-dismiss'); + expect(ondismiss).toHaveBeenCalled(); + }); + + it('should not be dismissible if not chosen', function () { + const alert = mq(Alert, { type: 'error', dismissible: false }); + expect(alert).not.toHaveElement('button.Alert-dismiss'); + }); +}); +``` + +#### Methods + +These are the custom methods that are available for mithril component tests: +* **`toHaveElement(selector)`** - Checks if the component has an element that matches the given selector. +* **`toContainRaw(content)`** - Checks if the component HTML contains the given content. + +To negate any of these methods, simply prefix them with `not.`. For example, `expect(alert).not.toHaveElement('button.Alert-dismiss');`. For more information, check out the [Jest docs](https://jestjs.io/docs/using-matchers). For example you may need to check how to [mock functions](https://jestjs.io/docs/mock-functions), or how to use `beforeEach` and `afterEach` to set up and tear down tests. + + + +## E2E Tests + +Coming Soon! diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/theme.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/theme.md new file mode 100644 index 000000000..7890be47f --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/theme.md @@ -0,0 +1,27 @@ +# Themes + +Flarum "themes" are just extensions. Typically, you'll want to use the `Frontend` extender to register custom [Less](https://lesscss.org/#overview) and JS. Of course, you can use other extenders too: for example, you might want to support settings to allow configuring your theme. + +You can indicate that your extension is a theme by setting the "extra.flarum-extension.category" key to "theme". For example: + +```json +{ + // other fields + "extra": { + "flarum-extension": { + "category": "theme" + } + } + // other fields +} +``` + +All this will do is show your extension in the "theme" section in the admin dashboard extension list. + +## Less Variable Customization + +You can define new Less variables in your extension's Less files. There currently isn't an extender to modify Less variable values in the PHP layer, but this is planned for future releases. + +## Switching Between Themes + +Flarum doesn't currently have a comprehensive system that would support switching between themes. This is planned for future releases. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md new file mode 100644 index 000000000..7ba6adcbf --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-1_0.md @@ -0,0 +1,257 @@ +# Updating For 1.0 + +Flarum version 1.0 is the long-awaited stable release! This release brings a number of refactors, cleanup, and small improvements that should make your Flarum experience just a bit better! + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Full Stack + +### Translations and transChoice + +#### Background + +Historically, Flarum has used Symfony for backend translations, and a port for frontend translations to keep format consistent. There are a few limitations to this approach though: + +- Developers need to decide between using `trans` or `transChoice` for pluralization +- The pluralization format is proprietary to Symfony +- We have to maintain the JS port ourselves +- Keys for values provided to backend translations need to be wrapped in curly braces. (e.g. `$this->translator->trans('some.translation', ['{username}' => 'Some Username!'])`). +- There's no support for complex applications (nested pluralization, non-number-based selection) +- As a result of the previous point, genderization is impossible. And that's kinda important for a lot of languages. + +### New System + +In v5, Symfony dropped their proprietary `transChoice` system in favor of the more-or-less standard [ICU MessageFormat](https://symfony.com/doc/5.2/translation/message_format.html). This solves pretty much every single one of the aforementioned issues. In this release, Flarum will be fully switching to ICU MessageFormat as well. What does this mean for extensions? + +- `transChoice` should not be used at all; instead, the variable passed for pluralization should be included in the data. +- Keys for backend translations no longer need to be surrounded by curly braces. +- Translations can now use the [`select` and `plural`](https://symfony.com/doc/5.2/translation/message_format.html) formatter syntaxes. For the `plural` formatter, the `offset` parameter and `#` magic variables are supported. +- These `select` and `plural` syntaxes can be nested to arbitrary depth. This is often a bad idea though (beyond, say, 2 levels), as things can get unnecessarily complex. + +No change to translation file naming is necessary (Symfony docs say that an `+intl-icu` suffix is necessary, but Flarum will now interpret all translation files as internationalized). + +#### Future Changes + +In the future, this will serve as a basis for additional features: + +- Translator preprocessors will allow extensions to modify arguments passed to translations. This will enable genderization (extensions could automatically extract a gender field from any objects of type "user" passed in). +- We could support internationalized "magic variables" for numbers: currently, `one` is supported, but others (`few`, `many`, etc) currently aren't. +- We could support ordinal formatting in additional to just plural formatting. + +#### Changes Needed in Extensions + +The `transChoice` methods in the frontend and backend have been removed. The `trans` method should always be used for translating, regardless of pluralization. If a translation requires pluralization, make sure you pass in the controlling variable as one of the arguments. + +In the frontend, code that looked like this: + +```js +app.translator.transChoice('some-translation', guestCount, {host: hostName}); +``` + +should be changed to: + +```js +// This uses ES6 key-property shorthand notation. {guestCount: guestCount} is equivalent to {guestCount} +app.translator.trans('some-translation', {host: hostName, guestCount }); +``` + +Similarly, in the backend, + +```php +$translator->transChoice('some-translation', $guestCount, ['{host}' => $hostName]); +``` + +should be changed to: + +```php +$translator->trans('some-translation', ['host' => $hostName, 'guestCount' => $guestCount]); +``` + +Note that in the backend, translation keys were previously wrapped in curly braces. This is no longer needed. + +#### Changes Needed in Translations + +Translations that aren't using pluralization don't need any changes. + +Pluralized translations should be changed as follows: + +`For {count} minute|For {count} minutes` + +to + +`{count, plural, one {For # minute} other {For # minutes}}` + +Note that in this example, `count` is the variable that controls pluralization. If a different variable were used (such as guestCount in the example above), this would look like: + +`{guestCount, plural, one {For # minute} other {For # minutes}}` + +See [our i18n docs](i18n.md) for more information. + +### Permissions Changes + +For a long time, the `viewDiscussions` and `viewUserList` permissions have been confusing. Despite their names: + +- `viewDiscussions` controls viewing both discussions and users. +- `viewUserList` controls searching users, not viewing user profiles. + +To clear this up, in v1.0, these permissions have been renamed to `viewForum` and `searchUsers` respectively. A migration in core will automatically adjust all permissions in the database to use the new naming. However, any extension code using the old name must switch to the new ones immediately to avoid security issues. To help the transfer, a warning will be thrown if the old permissions are referenced. + +We have also slightly improved tag scoping for permissions. Currently, permissions can be applied to tags if: + +- The permission is `viewForum` +- The permission is `startDiscussion` +- The permission starts with `discussion.` + +However, this doesn't work for namespaced permissions (`flarum-acme.discussion.bookmark`), or permissions that don't really have anything to do with discussions, but should still be scoped (e.g. `viewTag`). To counter this, a `tagScoped` attribute can be used on the object passed to [`registerPermission`](admin.md) to explicitly indicate whether the permission should be tag scopable. If this attribute is not provided, the current rules will be used to determine whether the permission should be tag scopable. + +## Frontend + +### Tooltip Changes + +The `flarum/common/components/Tooltip` component has been introduced as a simpler and less framework-dependent way to add tooltips. If your code is creating tooltips directly (e.g. via `$.tooltip()` in `oncreate` methods), you should wrap your components in the `Tooltip` component instead. For example: + +```tsx + + + +``` + +See [the source code](https://github.com/flarum/core/blob/master/js/src/common/components/Tooltip.tsx) for more examples and instructions. + +See [the PR](https://github.com/flarum/core/pull/2843/files) for examples of how to change existing code to use tooltips. + +### PaginatedListState + +The `flarum/common/states/PaginatedListState` state class has been introduced to abstract away most of the logic of `DiscussionListState` and `NotificationListState`. It provides support for loading and displaying paginated lists of JSON:API resources (usually models). In future releases, we will also provide an `PaginatedList` (or `InfiniteScroll`) component that can be used as a base class for these paginated lists. + +Please see [the source code](https://github.com/flarum/core/blob/master/js/src/common/states/PaginatedListState.ts) for a list of methods. + +Note that `flarum/forum/states/DiscussionListState`'s `empty` and `hasDiscussions` methods have been removed, and replaced with `isEmpty` and `hasItems` respectively. This is a breaking change. + +### New Loading Spinner + +The old `spin.js` based loading indicator has been replaced with a CSS-based solution. For the most part, no changes should be needed in extensions, but in some cases, you might need to update your spinner. This change also makes it easier to customize the spinner. + +See [this discussion](https://discuss.flarum.org/d/26994-beta16-using-the-new-loading-spinner) for more information. + +### classList util + +Ever wrote messy code trying to put together a list of classes for some component? Well, no longer! The [clsx library](https://www.npmjs.com/package/clsx) is now available as the `flarum/common/utils/classList` util. + +### User List + +An extensible user list has been added to the admin dashboard. In future releases, we hope to extract a generic model table component that can be used to list any model in the admin dashboard. + +See [the source code](https://github.com/flarum/core/blob/master/js/src/admin/components/UserListPage.tsx#L41) for a list of methods to extend, and examples of how columns should look like (can be added by extending the `columns` method and adding items to the [ItemList](frontend.md)). + +### Miscellaneous + +- Components should now call `super` for ALL Mithril lifecycle methods they define. Before, this was only needed for `oninit`, `onbeforeupdate`, and `oncreate`. Now, it is also needed in `onupdate`, `onbeforeremove`, and `onremove`. See [this GitHub issue](https://github.com/flarum/core/issues/2446) for information on why this change was made. +- The `flarum/common/utils/insertText` and `flarum/common/utils/styleSelectedText` utils have been moved to core from `flarum/markdown`. See `flarum/markdown` for an example of usage. +- The `extend` and `override` utils can now modify several methods at once by passing in an array of method names instead of a single method name string as the second argument. This is useful for extending the `oncreate` and `onupdate` methods at once. +- The `EditUserModal` component is no longer available through the `flarum/forum` namespace, it has been moved to `flarum/common`. Imports should be adjusted. +- The `Model` and `Route` JS extenders have been removed for now. There aren't currently used in any extensions that we know of. We will be reintroducing JS extenders during v1.x releases. +- The `Search` component can now be used with the `SearchState` state class. Previously, `SearchState` was missing the `getInitialSearch` method expected by the `Search` component. + +## Backend + +### Filesystem Extenders + +In this release, we refactored our use of the filesystem to more consistently use [Laravel's filesystem API](https://laravel.com/docs/8.x/filesystem). Extensions can now declare new disks, more easily use core's `flarum-assets` and `flarum-avatars` disks, and create their own storage drivers, enabling CDN and cloud storage support. + +### Compat and Closure Extenders + +In early Flarum versions, the `extend.php` file allowed arbitrary functions that allowed execution of arbitrary code one extension boot. For example: + +```php +return [ + // other extenders + function (Dispatcher $events) { + $events->subscribe(Listener\FilterDiscussionListByTags::class); + $events->subscribe(Listener\FilterPostsQueryByTag::class); + $events->subscribe(Listener\UpdateTagMetadata::class); + } +]; +``` + +This approach was difficult to maintain and provide a well-tested public API for, frequently resolved classes early (breaking all sorts of things), and was not very descriptive. With the extender API completed in beta 16, this approach is no longer necessary. Support for these closures has been removed in this stable version. + +One type of functionality for which the extender replacement isn't obvious is container bindings ([e.g. flarum/pusher](https://github.com/flarum/pusher/blob/v0.1.0-beta.14/extend.php#L33-L49)). This can be done with via the service provider extender (e.g. [a newer version of flarum/pusher](https://github.com/flarum/pusher/blob/master/extend.php#L40-L41)). + +If you are unsure about which extenders should be used to replace your use of callbacks in `extend.php`, or are not sure that such an extender exists, please comment so below or reach out! We're in the final stages of finishing up the extender API, so now is the time to comment. + +### Scheduled Commands + +The [fof/console](https://github.com/FriendsOfFlarum/console) library has been a popular way to schedule commands (e.g. for publishing scheduled posts, running DB-heavy operations, etc) for several release. In Flarum 1.0, this functionality has been brought into core's `Console` extender. See our [console extension documentation](console.md) for more information on how to create schedule commands, and our [console user documentation](../console.md) for more information on how to run scheduled commands. + +### Eager Loading Extender + +As part of solving [N+1 Query issues](https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/) in some [Flarum API endpoints](https://github.com/flarum/core/issues/2637), we have introduced a `load` method on the `ApiController` extender that allows you to indicate relations that should be eager loaded. + +This should be done if you know a relation will always be included, or will always be referenced by controller / permission logic. For example, we will always need the tags of a discussion to check what permissions a user has on that discussion, so we should eager load the discussion's `tags` relationship. For example: + +```php +return [ + // other extenders + (new Extend\ApiController(FlarumController\ListDiscussionsController::class)) + ->addInclude(['tags', 'tags.state', 'tags.parent']) + ->load('tags'), +]; +``` + +### RequestUtil + +The `Flarum\Http\RequestUtil`'s `getActor` and `withActor` should be used for getting/setting the actor (user) on requests. `$request->getAttribute('actor')` and `$request->withAttribute('actor')` are deprecated, and will be removed in v2.0. + +### Miscellaneous + +- The `Formatter` extender now has an `unparse` method that allows modifying XML before unparsing content. +- All route names must now be unique. In beta 16, uniqueness was enforced per-method; now, it is mandatory for all routes. +- API requests sent through `Flarum\Api\Client` now run through middleware, including `ThrottleApi`. This means that it is now possible to throttle login/registration calls. +- In beta 16, registering custom [searchers](search.md) was broken. It has been fixed in stable. +- The `post_likes` table in the [flarum/likes](https://github.com/flarum/likes) extension now logs the timestamp when likes were created. This isn't used in the extension, but could be used in other extensions for analytics. +- The `help` attribute of [admin settings](admin.md) no longer disappears on click. +- The `generate:migration` console command has been removed. The [Flarum CLI](https://discuss.flarum.org/d/26525-rfc-flarum-cli-alpha) should be used instead. +- The `GambitManager` util class is now considered internal API, and should not be used directly by extensions. +- The `session` attribute is no longer available on the `User` class. This caused issues with queue drivers, and was not conceptually correct (a user can have multiple sessions). The current session is still available via the `$request` instance. +- The `app`, `base_path`, `public_path`, `storage_path`, and `event` global helpers have been restored, but deprecated perpetually. These exist in case Laravel packages need them; they **should not** be used directly by Flarum extension code. The `flarum/laravel-helpers` package has been abandoned. +- The following deprecated features from beta 16 have been removed: + - The `TextEditor`, `TextEditorButton`, and `SuperTextarea` components are no longer exported through the `flarum/forum` namespace, but through `flarum/common` (with the exception of `SuperTextarea`, which has been replaced with `flarum/common/utils/BasicEditorDriver`). + - Support for `Symfony\Component\Translation\TranslatorInterface` has been removed, `Symfony\Contracts\Translation\TranslatorInterface` should be used instead. + - All backwards compatibility layers for the [beta 16 access token refactors](update-b16.md#access-token-and-authentication-changes) have been removed + - The `GetModelIsPrivate` event has been removed. The `ModelPrivate` extender should be used instead. + - The `Searching` (for both `User` and `Discussion` models), `ConfigureAbstractGambits`, `ConfigureDiscussionGambits`, and `ConfigureUserGambits` events have been removed. The `SimpleFlarumSearch` extender should be used instead. + - The `ConfigurePostsQuery` event has been removed. The `Filter` extender should be used instead. + - The `ApiSerializer` extender's `mutate` method has been removed. The same class's `attributes` method should be used instead. + - The `SearchCriteria` and `SearchResults` util classes have been removed. `Flarum\Query\QueryCriteria` and `Flarum\Query\QueryResults` should be used instead. + - The `pattern` property of `AbstractRegexGambit` has been removed; the `getGambitPattern` method is now a required abstract method. + - The `AbstractSearch` util class has been removed. `Flarum\Search\SearchState` and `Flarum\Filter\FilterState` should be used instead. + - The `CheckingPassword` event has been removed, the `Auth` extender should be used instead. + +## Tags Extension Changes + +As mentioned above, [tag scopable permissions](#permissions-changes) can now be explicitly declared. + +We've also made several big refactors to significantly improve tags performance. + +Firstly, the [Tag](https://github.com/flarum/tags/blob/d093ca777ba81f826157522c96680717d3a90e24/src/Tag.php#L38-L38) model's static `getIdsWhereCan` and `getIdsWhereCannot` methods have been removed. These methods scaled horribly on forums with many tags, sometimes adding several seconds to response time. + +These methods have been replaced with a `whereHasPermission` [Eloquent dynamic scope](https://laravel.com/docs/8.x/eloquent#dynamic-scopes) that returns a query. For example: + +`Tag::whereHasPermission($actor, 'viewDiscussions)`. + +That query can then be used in other DB queries, or further constricted to retrieve individual tags. + +Secondly, we no longer load in all tags as part of the initial payload. The initial payload contains all top-level primary tags, and the top 3 secondary tags. Other tags are loaded in as needed. Future releases will paginate secondary tags. This should enable forums to have thousands of secondary tags without significant performance impacts. These changes mean that extensions should not assume that all tags are available in the model store. + +## Testing Library Changes + +- Bundled extensions will not be automatically enabled; all enabled extensions must be specified in that test case. +- `setting` and `config` methods have been added that allow configuring settings and config.php values before the tested application boots. See [the testing docs](testing.md) for more information. +- The `php flarum test:setup` command will now drop the existing test DB tables before creating the database. This means that you can run `php flarum test:setup` to ensure a clean database without needing to go into the database and drop tables manually. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md new file mode 100644 index 000000000..ed17364ed --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-1_x.md @@ -0,0 +1,139 @@ +# Updating For 1.x + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## 1.7 + +### Frontend + +- Frontend extenders similar to the backend have been added, we highly recommend using them instead of the old method (https://docs.flarum.org/extend/models#adding-new-models-1), (https://docs.flarum.org/extend/routes#frontend-routes). +- There is a new tag selection component (https://github.com/flarum/framework/blob/360a2ba1d886df3fc6d326be932c5431ee9df8cf/extensions/tags/js/src/common/components/TagSelectionModal.tsx). + +### Backend + +- Support for php 8.2, deprecations are still thrown by some packages, the testing workflow has been updated to ignore deprecations on 8.2 +- The `/api` endpoint now contains the actor as an included relationship. +- The `Model::dateAttribute($attribute)` extender is deprecated, use `Model::cast($attribute, 'datetime')` instead. + +### Tooling + +- New `phpstan` package to run static code analysis on your extensions for code safety (https://docs.flarum.org/extend/static-code-analysis). +- New `jest-config` package to run frontend unit and component tests (https://docs.flarum.org/extend/testing). + +## 1.6 Changes + +### Backend + +- Added customizable session drivers through the `Session` extender. + +## 1.5 Changes + +### Frontend + +- More portions of the frontend are now written in TypeScript, providing a better extension development experience. +- Modals can be used in stacks, allowing for multiple modals to be open at once. This is useful for modals that open other modals: `app.modal.show(ModalComponent, { attrs }, true)`. + +### Backend + +- There is a new `createTableIfNotExists` migration helper, which can be used to create tables only if they don't already exist. + +## 1.4 Changes + +No developer-facing changes were made in Flarum v1.4. + +## 1.3 Changes + +Flarum v1.3 included mostly QoL improvements. Below are listed note worthy changes for extension developers: + +### Frontend + +- More portions of the frontend are now written in TypeScript, providing a better extension development experience. +- Frontend errors will no longer cause the forum to crash into a NoJs page. The extension will fail to execute its frontend code (initializer) and display an error to the admin through an alert, and to all users through the console. The frontend will continue to execute without the extension's frontend changes. +- The markdown toolbar can now be used on the admin side. + +### Backend + +- Calculation of the `number` attribute on `posts` has changed and no longer relies on the discussion model's `post_number_index` attribute which is now deprecated and will be removed in 2.0 +- Extension event listeners are now added after core even listeners, this should generally cause no changes in behavior. + +### Tooling + +- The backend tests workflow now automatically fails tests if there are any PHP warnings and notices. + +## 1.2 Changes + +Flarum v1.2 included quite a few bugfixes, internal refactors, and new features. The following recaps the most important changes for extension developers: + +### Frontend + +- Flarum core now passes TypeScript type checking (on the portion written in TypeScript). Additionally, major portions of the frontend (models, the application instance, and others) are now written in TypeScript. These changes should make it much easier and more fruitful to write extensions in TypeScript. +- Instead of directly using Less variables in CSS code, core now uses CSS variables. For the most part, we've just created CSS variables and set their values to the Less variables. This should make theming and customizing CSS a lot easier. https://github.com/flarum/core/pull/3146. +- Dropdowns can now be lazy-drawn to improve performance. You can do this by setting the lazy draw attr to "true". https://github.com/flarum/core/pull/2925. +- [Textarea-type settings](https://github.com/flarum/core/pull/3141) are now supported through the `app.extensionData.registerSetting` util. +- You can now use Webpack 5 to bundle your extension's code. This will offer minor bundle size improvements. +- A new `flarum/common/components/ColorPreviewInput` component [has been added](https://github.com/flarum/core/pull/3140). It can be used directly, or through the `color-preview` type when registered via `app.extensionData.registerSetting`. +- Extensions can now [modify the minimum search length](https://github.com/flarum/core/pull/3130) of the `Search` component. +- The following components are now extensible: + - The "colors" part of the Appearance page in the admin dashboard: https://github.com/flarum/core/pull/3186 + - The `StatusWidget` dropdown in the admin dashboard: https://github.com/flarum/core/pull/3189 + - `primaryControls` in the notification list: https://github.com/flarum/core/pull/3204 +- Extensions now have finer control over positioning when adding elements to the DiscussionPage sidebar items: https://github.com/flarum/core/pull/3165 +- + +### Backend + +- An [extender for settings defaults](https://github.com/flarum/core/pull/3127) has been added. This should be used instead of the `addSettings` migration helper, which has been deprecated. +- You can now [generate Less variables from setting values](https://github.com/flarum/core/pull/3011) via the `Settings` extender. +- Extensions can now [override/supplement blade template namespaces](https://github.com/flarum/core/pull/3167) through the `View` extender, meaning custom blade templates can be used instead of the default ones added by core or extensions. +- You can now define [custom Less functions through PHP](https://github.com/flarum/core/pull/3190), allowing you to use some backend logic in your Less theming. +- Extensions can now create [custom page title drivers](https://github.com/flarum/core/pull/3109/files) for titles in server-returned HTML. +- Custom logic can now be used when [deciding which relations to eager-load](https://github.com/flarum/core/pull/3116). +- Events [are now dispatched](https://github.com/flarum/core/pull/3203) for the `Notification\Read` and `Notification\ReadAll` events. +- An `ImageManager` instance is now [bound into the container](https://github.com/flarum/core/pull/3195), and can be configured to use either the `gd` or `imagick` backing drivers via the `"intervention.driver"` key in `config.php`. +- User IP addresses are now passed to the [API Client](https://github.com/flarum/core/pull/3124). +- A custom revision versioner implentation [can be set via container bindings](https://github.com/flarum/core/pull/3183) to customize how asset versions are named. +- A SlugManager instance [is now available](https://github.com/flarum/core/pull/3194) in blade templates via the `slugManager` variable. + +### Misc + +- Translations now support the `zero`, `one`, `two`, `few`, and `many` localized plural rules for `plural` ICU MessageFormat translations. This was done through the [`Intl.PluralRules` helper](https://github.com/flarum/core/issues/3072). +- Translations are now used for page titles, so that the format can be customized via language packs or [Linguist](https://discuss.flarum.org/d/7026-linguist-customize-translations-with-ease): https://github.com/flarum/core/pull/3077, https://github.com/flarum/core/pull/3228 +- API endpoints for retrieving single groups, as well as support for filtering groups on the plural get endpoint, [have been added](https://github.com/flarum/core/pull/3084). + + +### Tooling + + +- The `flarum-cli infra` command can now be used to update or enable various infrastructure features. You can now add the following to your extension in just one command: + - TypeScript + - Prettier for JS/TS formatting + - Backend testing with PHPUnit + - Code formatting with StyleCI + - EditorConfig support + - GitHub actions for automating testing, linting, type checking, and building. +- You can also exclude any files from these updates by adding their relative path to the "extra.flarum-cli" key's array in your extension's `composer.json` file. For example, if you wanted to exclude your tsconfig file from any updates by the infra system, the "extra.flarum-cli" key's value should be `["js/tsconfig.json"]`. +- The `flarum-cli audit infra` can be used to check that all infra modules your extension uses are up to date. The `--fix` flag can be used to automatically fix any issues, which has essentially the same effect as running `flarum-cli infra` for each outdated module. +- All `flarum-cli` commands can now be run with a `--no-interaction` flag to prevent prompts. Defaults will be used when possible, and errors will be thrown if a prompt is needed and there is no default. +- Frontend GH actions now support type-checking, as well as type coverage reports. + +## 1.1 Changes + +Flarum version 1.1 mostly focuses on bugfixes and quality-of-life improvements following our stable release earlier this year. These are mainly user-facing and internal infrastructure changes, so extensions are not significantly affected. + +### Frontend + +- Flarum now has an organization-wide prettier config package under [`@flarum/prettier-config`](https://github.com/flarum/prettier-config). +- Most custom (setting or data based) coloring in core is now done via [CSS custom properties](https://github.com/flarum/core/pull/3001). +- Typehinting for Flarum's globals are now [supported in extensions](https://github.com/flarum/core/pull/2992). +- You can now pass extra attrs to the `Select` component, and they will be [passed through to the DOM](https://github.com/flarum/core/pull/2959). +- The `DiscussionPage` component is now organized [as an item list](https://github.com/flarum/core/pull/3004), so it's easier for extensions to change its content. +- Extensions [can now edit](https://github.com/flarum/core/pull/2935) the `page` parameter of `PaginatedListState`. + +### Backend + +- Flarum now comes with a [Preload extender](https://github.com/flarum/core/pull/3057) for preloading any custom frontend assets. +- A new [Theme](https://github.com/flarum/core/pull/3008) extender now allows overriding Less files and internal imports. This allows themes to more easily completely replace Less modules. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md new file mode 100644 index 000000000..aaa98a2a5 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b10.md @@ -0,0 +1,53 @@ +# Updating For Beta 10 + +Beta 10 further solidifies the core architecture, offering new extenders as a stable, use-case-driven API for extending Flarum's core. A few small changes may necessitate updates to your extensions to make them compatible with Beta 10. These are detailed below. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Breaking Changes + +- The `Flarum\Event\GetDisplayName` class has been moved to `Flarum\User\Event\GetDisplayName`. +- The `Flarum\Http\Exception\ForbiddenException` has been removed. Use `Flarum\User\Exception\PermissionDeniedException` instead. +- The `assertGuest()` method of the `Flarum\User\AssertPermissionTrait` has been removed without replacement. +- Old error handling middleware and exception handler classes were removed (see "New Features" for more details): + - `Flarum\Api\Middleware\HandleErrors` + - `Flarum\Http\Middleware\HandleErrorsWithView` + - `Flarum\Http\Middleware\HandleErrorsWithWhoops` + - `Flarum\Api\ErrorHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + - `Flarum\Api\ExceptionHandler\FloodingExceptionHandler` + - `Flarum\Api\ExceptionHandler\IlluminateValidationExceptionHandler` + - `Flarum\Api\ExceptionHandler\InvalidAccessTokenExceptionHandler` + - `Flarum\Api\ExceptionHandler\InvalidConfirmationTokenExceptionHandler` + - `Flarum\Api\ExceptionHandler\MethodNotAllowedExceptionHandler` + - `Flarum\Api\ExceptionHandler\ModelNotFoundExceptionHandler` + - `Flarum\Api\ExceptionHandler\PermissionDeniedExceptionHandler` + - `Flarum\Api\ExceptionHandler\RouteNotFoundExceptionHandler` + - `Flarum\Api\ExceptionHandler\TokenMismatchExceptionHandler` + - `Flarum\Api\ExceptionHandler\ValidationExceptionHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + +## Recommendations + +- We tweaked the [recommended flarum/core version constraints for extensions](start.md#composer-json). We now recommend you mark your extension as compatible with the current and the upcoming beta release. (For beta.10, that would be any beta.10.x and beta.11.x version.) The core team will strive to make this work well by deprecating features before removing them. More details on this change in [this pull request](https://github.com/flarum/docs/pull/75). + +## New Features + +- New, extensible **error handling** stack in the `Flarum\Foundation\ErrorHandling` namespace: The `Registry` maps exceptions to "types" and HTTP status codes, `HttpFormatter` instances turn them into HTTP responses. Finally, `Reporter` instances are notified about unknown exceptions. + - You can build custom exception classes that will abort the current request (or console command). If they have semantic meaning to your application, they should implement the `Flarum\Foundation\KnownError` interface, which exposes a "type" that is used to render pretty error pages or dedicated error messages. + - More consistent use of HTTP 401 and 403 status codes. HTTP 401 should be used when logging in (i.e. authenticating) could make a difference; HTTP 403 is reserved for requests that fail because the already authenticated user is lacking permissions to do something. + - The `assertRegistered()` and `assertPermission()` methods of the `Flarum\User\AssertPermissionTrait` trait have been changed to match above semantics. See [this pull request](https://github.com/flarum/core/pull/1854) for more details. + - Error views are now determined based on error "type", not on status code (see [bdac88b](https://github.com/flarum/core/commit/bdac88b5733643b9c5dabae9e09a64d9f6e41d58)) +- **Queue support**: This release incorporates Laravel's illuminate/queue package, which allows offloading long-running tasks (such as email sending or regular cleanup jobs) onto a dedicated worker process. These changes are mostly under the hood, the next release(s) will start using the queue system for sending emails. By default, Flarum will use the "sync" queue driver, which executes queued tasks immediately. This is far from ideal and mostly guarantees a hassle-free setups. Production-grade Flarum installs are expected to upgrade to a more full-featured queue adapter. +- The `Flarum\Extend\LanguagePack` now accepts an optional path in its constructor. That way, language packs can store their locales in a different directory if they want to. +- The `formatContent()` method of `Flarum\Post\CommentPost` can now be called without an HTTP request instance, e.g. when rendering a post in an email template. + +## Deprecations + +- **Reminder**: In previous versions of Flarum, an extensions' main file was named `bootstrap.php`. This name will no longer be supported in the stable 0.1 release. Make sure your extension uses the name `extend.php`. +- Laravel's global string and array helpers (e.g. `str_contains()` and `array_only()`) are deprecated in favor of their class based alternatives (`Illuminate\Support\Str::contains()` and `Illuminate\Support\Arr::only()`). See the [announcement](https://laravel-news.com/laravel-5-8-deprecates-string-and-array-helpers) and [pull request](https://github.com/laravel/framework/pull/26898) for more information. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md new file mode 100644 index 000000000..ce6b1aca2 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b12.md @@ -0,0 +1,34 @@ +# Updating For Beta 12 + +Beta 12 packs several new features for extension developers, but also continues our cleanup efforts which results in a few changes, so please read this guide carefully to find out whether your extensions are affected. We invested extra effort to introduce new functionality in a backward-compatible manner or first deprecate functionality before it will be removed in the next release, in line with our [versioning recommendations](start.md#composer-json). + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Deprecations / Upcoming breaking changes + +- **Reminder**: In previous versions of Flarum, an extensions' main file was named `bootstrap.php`. This name will no longer be supported in the stable 0.1 release. Make sure your extension uses the name `extend.php`. +- PHP 7.1 support will be dropped in beta.13. +- Using library classes from the `Zend` namespace is now deprecated and will be removed in beta.13. Use the `Laminas` namespace instead. See [PR #1963](https://github.com/flarum/core/pull/1963). +- The `Flarum\Util\Str::slug()` method has been deprecated. Use `Illuminate\Support\Str::slug()` instead. +- The `Flarum\Event\ConfigureMiddleware` has been deprecated. We finally have a [proper replacement](middleware.md) - see "New Features" below. Therefore, it will be removed in beta.13. +- If you implement the `Flarum\Mail\DriverInterface`: + - Returning a plain array of field names from the `availableSettings()` method is deprecated, but still supported. It must now return an array of field names mapping to their type. See [the inline documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L25-L32) for more details. + - Implement the `validate()` method that will be required in beta.13. See [its documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L34-L48). + - Implement the `canSend()` method that will be required in beta.13. See [its documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L50-L54). + +## New Features + +- New **PHP extenders**: + - `Flarum\Extend\Middleware` offers methods for adding, removing or replacing middleware in our three middleware stacks (api, forum, admin). We also added [documentation](middleware.md) for this feature. + - `Flarum\Extend\ErrorHandling` lets you configure status codes and other aspects of our error handling stack depending on error types or exception classes. +- **JavaScript**: + - The `flarum/components/Select` component now supports a `disabled` prop. See [PR #1978](https://github.com/flarum/core/pull/1978). + +## Other changes / Recommendations + +- The `TextFormatter` library has been updated to (at least) version 2.3.6. If you are using it (likely through our own `Flarum\Formatter\Formatter` class), we recommend scanning [the library's changelog](https://github.com/s9e/TextFormatter/blob/2.3.6/CHANGELOG.md). +- The JS `slug()` helper from the `flarum/utils/string` module should only be used to *suggest* slugs to users, not enforce them. It does not employ any sophisticated transliteration logic like its PHP counterpart. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md new file mode 100644 index 000000000..1b19a9714 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b13.md @@ -0,0 +1,40 @@ +# Updating For Beta 13 + +Beta 13 ships with several new extenders to simplify building and maintaining extensions. We do our best to create backward compatibility changes. We recommend changing to new Extenders as soon as they are available. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Breaking Changes + +- Dropped support for PHP 7.1. +- Classes from the `Zend` namespace are now removed. Use the `Laminas` namespace instead. See [PR #1963](https://github.com/flarum/core/pull/1963). +- The `Flarum\Util\Str::slug()` method has been removed including the class. Use `Illuminate\Support\Str::slug()` instead. +- The `Flarum\Event\ConfigureMiddleware` has been removed. Use the [proper replacement](middleware.md). +- Several events used in Event Listeners have been removed, use their [replacement extender](start.md#extenders) instead. +- The LanguagePack extender only loads keys from extensions that are enabled. The translations loaded are based on the yaml files matching the [i18n namespace](i18n.md#appendix-a-standard-key-format). +- All notifications are now sent through the queue; without a queue driver they will run as usual. +- The implementation of avatar upload changed, we're [no longer storing files temporarily on disk](https://github.com/flarum/core/pull/2117). +- The SES mail driver [has been removed](https://github.com/flarum/core/pull/2011). +- Mail driver backward compatibility from beta 12 has been removed, use the new Mail extender or implement the [modified interface](https://github.com/flarum/core/blob/master/src/Mail/DriverInterface.php). + +## Recommendations + +- Beta 14 will ship with a rewrite in the frontend (javascript). If you're building for that release, make sure to follow our [progress](https://github.com/flarum/core/pull/2126). + +## New Features + +- A ton of new extenders: + - [Middleware extender](https://github.com/flarum/core/pull/2017) + - [Console extender](https://github.com/flarum/core/pull/2057) + - [CSRF extender](https://github.com/flarum/core/pull/2095) + - [Event extender](https://github.com/flarum/core/pull/2097) + - [Mail extender](https://github.com/flarum/core/pull/2012) + - [Model extender](https://github.com/flarum/core/pull/2100) + +## Deprecations + +- Several events [have been marked deprecated](https://github.com/flarum/core/commit/4efdd2a4f2458c8703aae654f95c6958e3f7b60b) to be removed in beta 14. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md new file mode 100644 index 000000000..deafdc960 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b14.md @@ -0,0 +1,757 @@ +# Updating For Beta 14 + +This release brings a large chunk of breaking changes - hopefully the last chunk of this size before our stable release. In order to prepare the codebase for the upcoming stable release, we decided it was time to modernize / upgrade / exchange some of the underlying JavaScript libraries that are used in the frontend. Due to the nature and size of these upgrades, we have to pass on some of the breaking changes to you, our extension developers. + +On the bright side, this overdue upgrade brings us closer to the conventions of best practices of [Mithril.js](https://mithril.js.org/), the mini-framework used for Flarum's UI. Mithril's 2.0 release sports a more consistent component interface, which should be a solid foundation for years to come. Where possible, we replicated old APIs, to ease the upgrade and give you time to do the full transition. Quite a few breaking changes remain, though - read more below. + +:::tip + +If you need help with the upgrade, our friendly community will gladly help you out either [on the forum](https://discuss.flarum.org/t/extensibility) or [in chat](https://flarum.org/chat/). + +::: + +To ease the process, we've clearly separated the changes to the [frontend (JS)](#frontend-javascript) from those in the [backend (PHP)](#backend-php) below. If your extension does not change the UI, consider yourself lucky. :-) + +A [summary of the frontend changes](#required-frontend-changes-recap) is available towards the end of this guide. + +## Frontend (JavaScript) + +### Mithril 2.0: Concepts + +Most breaking changes required by beta 14 are prompted by changes in Mithril 2. [Mithril's upgrade guide](https://mithril.js.org/migration-v02x.html) is an extremely useful resource, and should be consulted for more detailed information. A few key changes are explained below: + +#### props -> attrs; initProps -> initAttrs + +Props passed into component are now referred to as `attrs`, and can be accessed via `this.attrs` where you would prior use `this.props`. This was done to be closer to Mithril's preferred terminology. We have provided a temporary backwards compatibility layer for `this.props`, but recommend using `this.attrs`. + +Accordingly, `initProps` has been replaced with `initAttrs`, with a similar BC layer. + +#### m.prop -> `flarum/utils/Stream` + +Mithril streams, which were available via `m.prop` in Mithril 0.2, are now available via `flarum/utils/Stream`. `m.prop` will still work for now due to a temporary BC layer. + +#### m.withAttr -> withAttr + +The `m.withAttr` util has been removed from Mithril. We have provided `flarum/utils/withAttr`, which does the same thing. A temporary BC layer has been added for `m.withAttr`. + +#### Lifecycle Hooks + +In mithril 0.2, we had 2 "lifecycle hooks": + +`init`, an unofficial hook which ran when the component instance was initialized. + +`config`, which ran when components were created, and on every redraw. + + +Mithril 2 has the following hooks; each of which take `vnode` as an argument: + +- `oninit` +- `oncreate` +- `onbeforeupdate` +- `onupdate` +- `onbeforeremove` +- `onremove` + +Please note that if your component is extending Flarum's helper `Component` class, you must call `super.METHOD(vnode)` if using `oninit`, `oncreate`, and `onbeforeupdate`. + +More information about what each of these do can be found [in Mithril's documentation](https://mithril.js.org/lifecycle-methods.html). + +A trivial example of how the old methods map to the new is: + +```js +class OldMithrilComponent extends Component { + init() { + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + config(element, isInitialized) { + console.log('Code to run on every redraw AND when the element is first attached'); + + if (isInitialized) return; + + console.log('Code to execute only once when components are first created and attached to the DOM'); + + context.onunload = () => { + console.log('Code to run when the component is removed from the DOM'); + } + } + + view() { + // In mithril 0, you could skip redrawing a component (or part of a component) by returning a subtree retain directive. + // See https://mithril.js.org/archive/v0.2.5/mithril.render.html#subtree-directives + // dontRedraw is a substitute for logic; usually, this is used together with SubtreeRetainer. + if (dontRedraw()) return { subtree: 'retain' }; + + return

Hello World!

; + } +} + +class NewMithrilComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + oncreate(vnode) { + super.oncreate(vnode); + + console.log('Code to run when components are first created and attached to the DOM'); + } + + onbeforeupdate(vnode, oldVnode) { + super.onbeforeupdate(vnode); + + console.log('Code to run BEFORE diffing / redrawing components on every redraw'); + + // In mithril 2, if we want to skip diffing / redrawing a component, we return "false" in its onbeforeupdate lifecycle hook. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeupdate + // This is also typically used with SubtreeRetainer. + if (dontRedraw()) return false; + } + + onupdate(vnode) { + // Unlike config, this does NOT run when components are first attached. + // Some code might need to be replicated between oncreate and onupdate. + console.log('Code to run on every redraw AFTER the DOM is updated.'); + } + + onbeforeremove(vnode) { + // This is run before components are removed from the DOM. + // If a promise is returned, the DOM element will only be removed when the + // promise completes. It is only called on the top-level component that has + // been removed. It has no equivalent in Mithril 0.2. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeremove + return Promise.resolve(); + } + + onremove(vnode) { + console.log('Code to run when the component is removed from the DOM'); + } +} +``` + +#### Children vs Text Nodes + +In Mithril 0.2, every child of a vnode is another vnode, stored in `vnode.children`. For Mithril 2, as a performance optimization, vnodes with a single text child now store that text directly in `vnode.text`. For developers, that means that `vnode.children` might not always contain the results needed. Luckily, text being stored in `vnode.text` vs `vnode.children` will be the same each time for a given component, but developers should be aware that at times, they might need to use `vnode.text` and not `vnode.children`. + +Please see [the mithril documentation](https://mithril.js.org/vnodes.html#structure) for more information on vnode structure. + +#### Routing API + +Mithril 2 introduces a few changes in the routing API. Most of these are quite simple: + +- `m.route()` to get the current route has been replaced by `m.route.get()` +- `m.route(NEW_ROUTE)` to set a new route has been replaced by `m.route.set(NEW_ROUTE)` +- When registering new routes, a component class should be provided, not a component instance. + +For example: + +```js +// Mithril 0.2 +app.routes.new_page = { path: '/new', component: NewPage.component() } + +// Mithril 2.0 +app.routes.new_page = { path: '/new', component: NewPage } +``` + +Additionally, the preferred way of defining an internal (doesn't refresh the page when clicked) link has been changed. The `Link` component should be used instead. + +```js +// Mithril 0.2 +
Link Content + +// Mithril 2 +import Link from 'flarum/components/Link'; + +Link Content +``` + +You can also use `Link` to define external links, which will just render as plain `Children` html links. + +For a full list of routing-related changes, please see [the mithril documentation](https://mithril.js.org/migration-v02x.html). + +#### Redraw API + +Mithril 2 introduces a few changes in the redraw API. Most of these are quite simple: + +- Instead of `m.redraw(true)` for synchronous redraws, use `m.redraw.sync()` +- Instead of `m.lazyRedraw()`, use `m.redraw()` + +Remember that Mithril automatically triggers a redraw after DOM event handlers. The API for preventing a redraw has also changed: + +```js +// Mithril 0.2 + + +// Mithril 2 + +``` + +#### AJAX + +The `data` parameter of `m.request({...})` has been split up into `body` and `params`. + +For examples and other AJAX changes, see [the mithril documentation](https://mithril.js.org/migration-v02x.html#mrequest). + +#### Promises + +`m.deferred` has been removed, native promises should be used instead. For instance: + +```js +// Mithril 0.2 +const deferred = m.deferred(); + +app.store.find('posts').then(result => deferred.resolve(result)); + +return deferred.promise; + +// Mithril 2 +return app.store.find('posts'); +``` + +#### Component instances should not be stored + +Due to optimizations in Mithril's redrawing algorithms, [component instances should not be stored](https://mithril.js.org/components.html#define-components-statically,-call-them-dynamically). + +So whereas before, you might have done something like: + +```js +class ChildComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return

{this.counter}

; + } +} +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.child = new ChildComponent(); + } + + view() { + return ( +
+ + {this.child.render()} +
+ ) + } +} +``` + +That will no longer work. In fact; the Component class no longer has a render method. + +Instead, any data needed by a child component that is modified by a parent component should be passed in as an attr. For instance: + +```js +class ChildComponent extends Component { + view() { + return

{this.attrs.counter}

; + } +} + +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return ( +
+ + +
+ ) + } +} +``` + +For more complex components, this might require some reorganization of code. For instance, let's say you have data that can be modified by several unrelated components. In this case, it might be preferable to create a POJO "state instance' for this data. These states are similar to "service" singletons used in Angular and Ember. For instance: + +```js +class Counter { + constructor() { + this._counter = 0; + } + + increaseCounter() { + this._counter += 1; + } + + getCount() { + return this._counter; + } +} + +app.counter = new Counter(); + +extend(HeaderSecondary.prototype, 'items', function(items) { + items.add('counterDisplay', +
+

Counter: {app.counter.getCount()}

+
+ ); +}) + +extend(HeaderPrimary.prototype, 'items', function(items) { + items.add('counterButton', +
+ +
+ ); +}) +``` + +This "state pattern" can be found throughout core. Some non-trivial examples are: + +- PageState +- SearchState and GlobalSearchState +- NotificationListState +- DiscussionListState + +### Changes in Core + +#### Modals + +Previously, modals could be opened by providing a `Modal` component instance: + +```js +app.modal.show(new LoginModal(identification: 'prefilledUsername')); +``` + +Since we don't store component instances anymore, we pass in the component class and any attrs separately. + +```js +app.modal.show(LoginModal, {identification: 'prefilledUsername'}); +``` + +The `show` and `close` methods are still available through `app.modal`, but `app.modal` now points to an instance of `ModalManagerState`, not of the `ModalManager` component. Any modifications by extensions should accordingly be done to `ModalManagerState`. + +#### Alerts + +Previously, alerts could be opened by providing an `Alert` component instance: + +```js +app.alerts.show(new Alert(type: 'success', children: 'Hello, this is a success alert!')); +``` + +Since we don't store component instances anymore, we pass in a component class, attrs, children separately. The `show` method has 3 overloads: + +```js +app.alerts.show('Hello, this is a success alert!'); +app.alerts.show({type: 'success'}, 'Hello, this is a success alert!'); +app.alerts.show(Alert, {type: 'success'}, 'Hello, this is a success alert!'); +``` + +Additionally, the `show` method now returns a unique key, which can then be passed into the `dismiss` method to dismiss that particular alert. This replaces the old method of passing the alert instance itself to `dismiss`. + +The `show`, `dismiss`, and `clear` methods are still available through `app.alerts`, but `app.alerts` now points to an instance of `AlertManagerState`, not of the `AlertManager` component. Any modifications by extensions should accordingly be done to `AlertManagerState`. + +#### Composer + +Since we don't store a component instances anymore, a number of util methods from `Composer`, `ComposerBody` (and it's subclasses), and `TextEditor` have been moved onto `ComposerState`. + +For `forum/components/Composer`, `isFullScreen`, `load`, `clear`, `show`, `hide`, `close`, `minimize`, `fullScreen`, and `exitFullScreen` have been moved to `forum/states/ComposerState`. They all remain accessible via `app.composer.METHOD` + +A `bodyMatches` method has been added to `forum/states/ComposerState`, letting you check whether a certain subclass of `ComposerBody` is currently open. + +Various input fields are now stored as [Mithril Streams](https://mithril.js.org/stream.html) in `app.composer.fields`. For instance, to get the current composer content, you could use `app.composer.fields.content()`. Previously, it was available on `app.composer.component.content()`. **This is a convention that `ComposerBody` subclasses that add inputs should follow.** + +`app.composer.component` is no longer available. + +- Instead of `app.composer.component instanceof X`, use `app.composer.bodyMatches(X)`. +- Instead of `app.composer.component.props`, use `app.composer.body.attrs`. +- Instead of `app.composer.component.editor`, use `app.composer.editor`. + +For `forum/components/TextEditor`, the `setValue`, `moveCursorTo`, `getSelectionRange`, `insertAtCursor`, `insertAt`, `insertBetween`, `replaceBeforeCursor`, `insertBetween` methods have been moved to `forum/components/SuperTextarea`. + +Also for `forum/components/TextEditor`, `this.disabled` is no longer used; `disabled` is passed in as an attr instead. It may be accessed externally via `app.composer.body.attrs.disabled`. + +Similarly to Modals and Alerts, `app.composer.load` no longer accepts a component instance. Instead, pass in the body class and any attrs. For instance, + +```js +// Mithril 0.2 +app.composer.load(new DiscussionComposer({user: app.session.user})); + +// Mithril 2 +app.composer.load(DiscussionComposer, {user: app.session.user}) +``` + +Finally, functionality for confirming before unloading a page with an active composer has been moved into the `common/components/ConfirmDocumentUnload` component. + +#### Widget and DashboardWidget + +The redundant `admin/components/Widget` component has been removed. `admin/components/DashboardWidget` should be used instead. + +#### NotificationList + +For `forum/components/NotificationList`, the `clear`, `load`, `loadMore`, `parseResults`, and `markAllAsRead` methods have been moved to `forum/states/NotificationListState`. + +Methods for `isLoading` and `hasMoreResults` have been added to `forum/states/NotificationListState`. + +`app.cache.notifications` is no longer available; `app.notifications` (which points to an instance of `NotificationListState`) should be used instead. + +#### Checkbox + +Loading state in the `common/components/Checkbox` component is no longer managed through `this.loading`; it is now passed in as a prop (`this.attrs.loading`). + +#### Preference Saver + +The `preferenceSaver` method of `forum/components/SettingsPage` has been removed without replacement. This is done to avoid saving component instances. Instead, preferences should be directly saved. For instance: + +```js +// Old way +Switch.component({ + children: app.translator.trans('core.forum.settings.privacy_disclose_online_label'), + state: this.user.preferences().discloseOnline, + onchange: (value, component) => { + this.user.pushAttributes({ lastSeenAt: null }); + this.preferenceSaver('discloseOnline')(value, component); + }, +}) + +// Without preferenceSaver +Switch.component({ + children: app.translator.trans('core.forum.settings.privacy_disclose_online_label'), + state: this.user.preferences().discloseOnline, + onchange: (value) => { + this.discloseOnlineLoading = true; + + this.user.savePreferences({ discloseOnline: value }).then(() => { + this.discloseOnlineLoading = false; + m.redraw(); + }); + }, + loading: this.discloseOnlineLoading, +}) +``` + +A replacement will eventually be introduced. + +#### DiscussionListState + +For `forum/components/DiscussionList`, the `requestParams`, `sortMap`, `refresh`, `loadResults`, `loadMore`, `parseResults`, `removeDiscussion`, and `addDiscussion` methods have been moved to `forum/states/DiscussionListState`. + +Methods for `hasDiscussions`, `isLoading`, `isSearchResults`, and `empty` have been added to `forum/states/DiscussionListState`. + +`app.cache.discussions` is no longer available; `app.discussions` (which points to an instance of `DiscussionListState`) should be used instead. + +#### PageState + +`app.current` and `app.previous` no longer represent component instances, they are now instances of the `common/states/PageState` class. This means that: + +- Instead of `app.current instanceof X`, use `app.current.matches(X)` +- Instead of `app.current.PROPERTY`, use `app.current.get('PROPERTY')`. Please note that all properties must be exposed EXPLICITLY via `app.current.set('PROPERTY', VALUE)`. + +#### PostStream + +Logic from `forum/components/PostStreamScrubber`'s `update` method has been moved to `forum/components/PostStream`'s `updateScrubber` method. + +For `forum/components/PostStream`, the `update`, `goToFirst`, `goToLast`, `goToNumber`, `goToIndex`, `loadNearNumber`, `loadNearIndex`, `loadNext`, `loadPrevious`, `loadPage`, `loadRange`, `show`, `posts`, `reset`, `count`, and `sanitizeIndex` methods have been moved to `forum/states/PostStreamState`. + +Methods for `disabled` and `viewingEnd` have been added to `forum/states/PostStreamState`. + +#### SearchState and GlobalSearchState + +As with other components, we no longer store instances of `forum/components/Search`. As such, every `Search` component instance should be paired with a `forum/states/SearchState` instance. + +At the minimum, `SearchState` contains the following methods: + +- getValue +- setValue +- clear +- cache (adds a searched value to cache, meaning that we don't need to search for its results again) +- isCached (checks if a value has been searched for before) + +All of these methods have been moved from `Search` to `SearchState`. Additionally, Search's `stickyParams`, `params`, `changeSort`, `getInitialSearch`, and `clearInitialSearch` methods have been moved to `forum/states/GlobalSearchState`, which is now available via `app.search`. + +To use a custom search, you'll want to: + +1. Possibly create a custom subclass of `SearchState` +2. Create a custom subclass of `Search`, which overrides the `selectResult` method to handle selecting results as needed by your use case, and modify the `sourceItems` methods to contain the search sources you need. + +#### moment -> dayjs + +The `moment` library has been removed, and replaced by the `dayjs` library. The global `moment` can still be used for now, but is deprecated. `moment` and `dayjs` have very similar APIs, so very few changes will be needed. Please see the dayjs documentation [for more information](https://day.js.org/en/) on how to use it. + +#### Subtree Retainer + +`SubtreeRetainer` is a util class that makes it easier to avoid unnecessary redraws by keeping track of some pieces of data. When called, it checks if any of the data has changed; if not, it indicates that a redraw is not necessary. + +In mithril 0.2, its `retain` method returned a [subtree retain directive](https://mithril.js.org/archive/v0.1.25/mithril.render.html#subtree-directives) if no redraw was necessary. + +In mithril 2, we use its `needsRebuild` method in combination with `onbeforeupdate`. For instance: + +```js +class CustomComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + this.showContent = false; + + this.subtree = new SubtreeRetainer( + () => this.showContent, + ) + } + + onbeforeupdate() { + // If needsRebuild returns true, mithril will diff and redraw the vnode as usual. Otherwise, it will skip this redraw cycle. + // In this example, this means that this component and its children will only be redrawn when extra content is toggled. + return this.subtree.needsRebuild(); + } + + view(vnode) { + return
+ +

Hello World!{this.showContent ? ' Extra Content!' : ''}

+
; + } +} +``` + +#### attrs() method + +Previously, some components would have an attrs() method, which provided an extensible way to provide attrs to the top-level child vnode returned by `view()`. For instance, + +```js +class CustomComponent extends Component { + view() { + return

Hello World!

; + } + + attrs() { + return { + className: 'SomeClass', + onclick: () => console.log('click'), + }; + } +} +``` + +Since `this.attrs` is now used for attrs passed in from parent components, `attrs` methods have been renamed to `elementAttrs`. + +#### Children and .component + +Previously, an element could be created with child elements by passing those in as the `children` prop: + +```js +Button.component({ + className: 'Button Button--primary', + children: 'Button Text' +}); +``` + +This will no longer work, and will actually result in errors. Instead, the 2nd argument of the `component` method should be used: + +```js +Button.component({ + className: 'Button Button--primary' +}, 'Button Text'); +``` + +Children can still be passed in through JSX: + +```js + +``` + +#### Tag attr + +Because mithril uses 'tag' to indicate the actual html tag (or component class) used for a vnode, you can no longer pass `tag` as an attr to components extending Flarum's `Component` helper class. The best workaround here is to just use another name for this attr. + +#### affixSidebar + +The `affixSidebar` util has been removed. Instead, if you want to affix a sidebar, wrap the sidebar code in an `AffixedSidebar` component. For instance, + +```js +class OldWay extends Component { + view() { + return
+
+
+ +
Actual Page Content
+
+
+
; + } +} + +class NewWay extends Component { + view() { + return
+
+
+ + + +
Actual Page Content
+
+
+
; + } +} +``` + +#### Fragment + +**Warning: For Advanced Use Only** + +In some rare cases, we want to have extremely fine grained control over the rendering and display of some significant chunks of the DOM. These are attached with `m.render`, and do not experience automated redraws. Current use cases in core and bundled extensions are: + +- The "Reply" button that shows up when selecting text in a post +- The mentions autocomplete menu that shows up when typing +- The emoji autocomplete menu that shows up when typing + +For this purpose, we provide a helper class (`common/Fragment`), of which you can create an instance, call methods, and render via `m.render(DOM_ROOT, fragmentInstance.render())`. The main benefit of using the helper class is that it allows you to use lifecycle methods, and to access the underlying DOM via `this.$()`, like you would be able to do with a component. + +This should only be used when absolutely necessary. If you are unsure, you probably don't need it. If the goal is to not store component instances, the "state pattern" as described above is preferable. + +### Required Frontend Changes Recap + +Each of these changes has been explained above, this is just a recap of major changes for your convenience. + +- Component Methods: + - `view()` -> `view(vnode)` + - Lifecycle + - `init()` -> `oninit(vnode)` + - `config()` -> Lifecycle hooks `oncreate(vnode)` / `onupdate(vnode)` + - `context.onunload()` -> `onremove()` + - `SubtreeRetainer` -> `onbeforeupdate()` + - if present, `attrs()` method needs to be renamed -> convention `elementAttrs()` + - building component with `MyComponent.component()` -> `children` is now second parameter instead of a named prop/attr (first argument) -> JSX preferred +- Routing + - `m.route()` -> `m.route.get()` + - `m.route(name)` -> `m.route.set(name)` + - register routes with page class, not instance + - special case when passing props + - `` -> `` +- AJAX + - `m.request({...})` -> `data:` key split up into `body:` and `params:` + - `m.deferred` -> native `Promise` +- Redrawing + - `m.redraw(true)` -> `m.redraw.sync()` + - `m.redraw.strategy('none')` -> `e.redraw = false` in event handler + - `m.lazyRedraw()` -> `m.redraw()` + +#### Deprecated changes + +For the following changes, we currently provide a backwards-compatibility layer. This will be removed in time for the stable release. The idea is to let you release a new version that's compatible with Beta 14 to your users as quickly as possible. When you have taken care of the changes above, you should be good to go. For the following changes, we have bought you time until the stable release. Considering you have to make changes anyway, why not do them now? + +- `this.props` -> `this.attrs` +- static `initProps()` -> static `initAttrs()` +- `m.prop` -> `flarum/utils/Stream` +- `m.withAttr` -> `flarum/utils/withAttr` +- `moment` -> `dayjs` + +## Backend (PHP) + +### New Features + +#### Extension Dependencies + +Some extensions are based on, or add features to, other extensions. Prior to this release, there was no way to ensure that those dependencies were enabled before the extension that builds on them. Now, you cannot enable an extension unless all of its dependencies are enabled, and you cannot disable an extension if there are other enabled extensions depending on it. + +So, how do we specify dependencies for an extension? Well, all you need to do is add them as composer dependencies to your extension's `composer.json`! For instance, if we have an extension that depends on Tags and Mentions, our `composer.json` will look like this: + +```json +{ + "name": "my/extension", + "description": "Cool New Extension", + "type": "flarum-extension", + "license": "MIT", + "require": { + "flarum/core": "^0.1.0-beta.14", + "flarum/tags": "^0.1.0-beta.14", // Will mark tags as a dependency + "flarum/mentions": "^0.1.0-beta.14", // Will mark mentions as a dependency + } + // other config +} +``` + +#### View Extender + +Previously, when extensions needed to register Laravel Blade views, they could inject a view factory in `extend.php` and call it's `addNamespace` method. For instance, + +```php +// extend.php +use Illuminate\Contracts\View\Factory; + +return [ + function (Factory $view) { + $view->addNamespace(NAME, RELATIVE PATH); + } +] +``` + +This should NOT be used, as it will break views for all extensions that boot after yours. Instead, the `View` extender should be used: + +```php +// extend.php +use Flarum\Extend\View; + +return [ + (new View)->namespace(NAME, RELATIVE PATH); +] +``` + +#### Application and Container + +Although Flarum uses multiple components of the Laravel framework, it is not a pure Laravel system. In beta 14, the `Flarum\Foundation\Application` class no longer implements `Illuminate\Contracts\Foundation\Application`, and no longer inherits `Illuminate\Container\Container`. Several things to note: + +- The `app` helper now points to an instance of `Illuminate\Container\Container`, not `Flarum\Foundation\Application`. You might need to resolve things through the container before using them: for instance, `app()->url()` will no longer work; you'll need to resolve or inject an instance of `Flarum\Foundation\Config` and use that. +- Injected or resolved instances of `Flarum\Foundation\Application` can no longer resolve things through container methods. `Illuminate\Container\Container` should be used instead. +- Not all public members of `Illuminate\Contracts\Foundation\Application` are available through `Flarum\Foundation\Application`. Please refer to our [API docs on `Flarum\Foundation\Application`](https://api.docs.flarum.org/php/master/flarum/foundation/application) for more information. + +#### Other Changes + +- We are now using Laravel 6. Please see [Laravel's upgrade guide](https://laravel.com/docs/6.x/upgrade) for more information. Please note that we do not use all of Laravel. +- Optional params in url generator now work. For instance, the url generator can now properly generate links to posts in discussions. +- A User Extender has been added, which replaces the deprecated `PrepareUserGroups` and `GetDisplayName` events. +- Error handler middleware can now be manipulated by the middleware extender through the `add`, `remove`, `replace`, etc methods, just like any other middleware. +- `Flarum/Foundation/Config` and `Flarum/Foundation/Paths` can now be injected where needed; previously their data was accessible through `Flarum/Foundation/Application`. + +### Deprecations + +- `url` provided in `config.php` is now an array, accessible via `$config->url()`, for an instance of `Config` - [PR](https://github.com/flarum/core/pull/2271#discussion_r475930358) +- AssertPermissionTrait has been deprecated - [Issue](https://github.com/flarum/core/issues/1320) +- Global path helpers and path methods of `Application` have been deprecated, the injectable `Paths` class should be used instead - [PR](https://github.com/flarum/core/pull/2155) +- `Flarum\User\Event\GetDisplayName` has been deprecated, the `displayNameDriver` method of the `User` extender should be used instead - [PR](https://github.com/flarum/core/pull/2174) + +### Removals + +- Do NOT use the old closure notation for configuring view namespaces. This will break all extensions that boot after your extension. The `View` extender MUST be used instead. +- app()->url() will no longer work: [`Flarum\Http\UrlGenerator`](routes.md) should be injected and used instead. An instance of `Flarum\Http\UrlGenerator` is available in `blade.php` templates via `$url`. +- As a part of the Laravel 6 upgrade, the [`array_` and `str_` helpers](https://laravel.com/docs/6.x/upgrade#helpers) have been removed. +- The Laravel translator interface has been removed; the Symfony translator interface should be used instead: `Symfony\Component\Translation\TranslatorInterface` +- The Mandrill mail driver is no longer provided in Laravel 6, and has been removed. +- The following events deprecated in Beta 13 [have been removed](https://github.com/flarum/core/commit/7d1ef9d89161363d1c8dea19cf8aebb30136e9e3#diff-238957b67e42d4e977398cd048c51c73): + - `AbstractConfigureRoutes` + - `ConfigureApiRoutes` - Use the `Routes` extender instead + - `ConfigureForumRoutes` - Use the `Frontend` or `Routes` extenders instead + - `ConfigureLocales` - Use the `LanguagePack` extender instead + - `ConfigureModelDates` - Use the `Model` extender instead + - `ConfigureModelDefaultAttributes` - Use the `Model` extender instead + - `GetModelRelationship` - Use the `Model` extender instead + - `Console\Event\Configuring` - Use the `Console` extender instead + - `BioChanged` - User bio has not been a core feature for several releases diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md new file mode 100644 index 000000000..313f78557 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b15.md @@ -0,0 +1,60 @@ +# Updating For Beta 15 + +Beta 15 features multiple new extenders, a total redesign of the admin dashboard, and several other interesting new features for extensions. As before, we have done our best to provide backwards compatibility layers, and we recommend switching away from deprecated systems as soon as possible to make your extensions more stable. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## New Features / Deprecations + +### 扩展器 + +- `Flarum\Api\Event\WillGetData` and `Flarum\Api\Event\WillSerializeData` have been deprecated, the `ApiController` extender should be used instead +- `Flarum\Api\Event\Serializing` and `Flarum\Event\GetApiRelationship` have been deprecated, the `ApiSerializer` extender should be used instead +- `Flarum\Formatter\Event\Parsing` has been deprecated, the `parse` method of the `Formatter` extender should be used instead +- `Flarum\Formatter\Event\Rendering` has been deprecated, the `render` method of the `Formatter` extender should be used instead +- `Flarum\Notification\Event\Sending` has been deprecated, the `driver` method of the `Notification` extender should be used instead + - Please note that the new notification driver system is not an exact analogue of the old `Sending` event, as it can only add new drivers, not change the functionality of the default notification bell alert driver. If your extension needs to modify **how** or **to whom** notifications are sent, you may need to replace `Flarum\Notification\NotificationSyncer` on the service provider level +- `Flarum\Event\ConfigureNotificationTypes` has been deprecated, the `type` method of the `Notification` extender should be used instead +- `Flarum\Event\ConfigurePostTypes` has been deprecated, the `type` method of the `Post` extender should be used instead +- `Flarum\Post\Event\CheckingForFlooding` has been deprecated, as well as `Flarum\Post\Floodgate`. They have been replaced with a middleware-based throttling system that applies to ALL requests to /api/*, and can be configured via the `ThrottleApi` extender. Please see our [api-throttling](api-throttling.md) documentation for more information. +- `Flarum\Event\ConfigureUserPreferences` has been deprecated, the `registerPreference` method of the `User` extender should be used instead +- `Flarum\Foundation\Event\Validating` has been deprecated, the `configure` method of the `Validator` extender should be used instead + +- The Policy system has been reworked a bit to be more intuitive. Previously, policies contained both actual policies, which determine whether a user can perform some ability, and model visibility scopers, which allowed efficient restriction of queries to only items that users have access to. See the [authorization documentation](authorization.md) for more information on how to use the new systems. Now: + - `Flarum\Event\ScopeModelVisibility` has been deprecated. New scopers can be registered via the `ModelVisibility` extender, and any `Eloquent\Builder` query can be scoped by calling the `whereVisibleTo` method on it, with the ability in question as an optional 2nd argument (defaults to `view`). + - `Flarum\Event\GetPermission` has been deprecated. Policies can be registered via the `Policy` extender. `Flarum\User\User::can` has not changed. Please note that the new policies must return one of `$this->allow()`, `$this->deny()`, `$this->forceAllow()`, `$this->forceDeny()`, not a boolean. + +- A `ModelUrl` extender has been added, allowing new slug drivers to be registered. This accompanies Flarum's new slug driving system, which allows for extensions to define custom slugging strategies for sluggable models. The extender supports sluggable models outside of Flarum core. Please see our [model slugging](slugging.md) documentation for more information. +- A `Settings` extender has been added, whose `serializeToForum` method makes it easy to serialize a setting to the forum. +- A `ServiceProvider` extender has been added. This should be used with extreme caution for advanced use cases only, where there is no alternative. Please note that the service provider layer is not considered public API, and is liable to change at any time, without notice. + +### Admin UX Redesign + +The admin dashboard has been completely redesigned, with a focus on providing navbar pages for each extension. The API for extensions to register settings, permissions, and custom pages has also been greatly simplified. You can also now update your extension's `composer.json` to provide links for funding, support, website, etc that will show up on your extension's admin page. Please see [our Admin JS documentation](admin.md) for more information on how to use the new system. + +### Other New Features + +- On the backend, the route name is now available via `$request->getAttribute('routeName')` for controllers, and for middleware that run after `Flarum\Http\Middleware\ResolveRoute.php`. +- `Flarum\Api\Controller\UploadImageController.php` can now be used as a base class for controllers that upload images (like for the logo and favicon). +- Automatic browser scroll restoration can now be disabled for individual pages [see our frontend page documentation for more info](frontend-pages.md). + +## Breaking Changes + +- The following deprecated frontend BC layers were removed: + - `momentjs` no longer works as an alias for `dayjs` + - `this.props` and `this.initProps` no longer alias `this.attrs` and `this.initAttrs` for the `Component` base class + - `m.withAttr` and `m.stream` no longer alias `flarum/utils/withAttr` and `flarum/utils/Stream` + - `app.cache.discussionList` has been removed + - `this.content` and `this.editor` have been removed from `ComposerBody` + - `this.component`, `this.content`, and `this.value` have been removed from `ComposerState` +- The following deprecated backend BC layers were removed: + - The `publicPath`, `storagePath`, and `vendorPath` methods of `Flarum\Foundation\Application` have been removed + - The `base_path`, `public_path`, and `storage_path` global helpers have been removed + - The `getEmailSubject` method of `Flarum\Notification\MailableInterface` MUST now take a translator instance as an argument + - `Flarum\User\AssertPermissionTrait` has been removed, the analogous methods on `Flarum\User\User` should be used instead + - The `Flarum\Event\PrepareUserGroups` event has been removed, use the `User` extender instead + - The `Flarum\User\Event\GetDisplayName` event has been removed, use the display name driver feature of the `User` extender instead diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md new file mode 100644 index 000000000..e99c0536a --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b16.md @@ -0,0 +1,138 @@ +# Updating For Beta 16 + +Beta 16 finalizes the PHP extender API, introduces a testing library and JS typings, switches to using namespaces for JS imports, increases extension dependency robustness, and allows overriding routes, among other features. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Frontend + +- A new editor driver abstraction has been introduced, which allows extensions to override the default textarea-based editor with more advanced solutions. +- The `TextEditor` and `TextEditorButton` components, as well as the `BasicEditorDriver` util (which replaces `SuperTextarea`) have been moved from `forum` to `common`. +- The `forum`, `admin`, and `common` namespaces should be used when importing. So instead of `import Component from 'flarum/Component'`, use `import Component from 'flarum/common/Component`. Support for the old import styles will be deprecated through the stable release, and removed with Flarum 2.0. +- A typing library has been released to support editor autocomplete for frontend development, and can be installed in your dev environment via `npm install --save-dev flarum@0.1.0-beta.16`. +- Extension categories have been simplified down to `feature`, `theme`, and `language`. + +## Backend + +### 扩展器 + +- All extenders that support callbacks/closures now support global functions like `'boolval'` and array-type functions like `[ClassName::class, 'methodName']`. +- The `Settings` extender's `serializeToFrontend` method now supports a default value as the 4th argument. +- The `Event` extender now supports registering subscribers for multiple events at once via a `subscribe` method. +- The `Notification` extender now has a `beforeSending` method, which allows you to adjust the list of recipients before a notification is sent. +- The `mutate` method of `ApiSerializer` has been deprecated, and renamed to `attributes`. +- `remove` methods on the `Route` and `Frontend` extenders can be used to remove (and then replace) routes. +- A `ModelPrivate` extender replaces the `GetModelIsPrivate` event, which has been deprecated. +- Methods on the `Auth` extender replace the `CheckingPassword` event, which has been deprecated. +- All search-related events are now deprecated in favor of the `SimpleFlarumSearch` and `Filter` extenders; this is explained in more detail below. + +### Laravel and Symfony + +Beta 16 upgrades from v6.x to v8.x of Laravel components and v4 to v5 of Symfony components. Please see the respective upgrade guides of each for changes you might need to make to your extensions. The most applicable change is the deprecation of `Symfony\Component\Translation\TranslatorInterface` in favor of `Symfony\Contracts\Translation\TranslatorInterface`. The former will be removed in beta 17. + +### Helper Functions + +The remaining `app` and `event` global helper functions have been deprecated. `app` has been replaced with `resolve`, which takes the name of a container binding and resolves it through the container. + +Since some Flarum extensions use Laravel libraries that assume some global helpers exist, we've recreated some commonly used helpers in the [flarum/laravel-helpers](https://github.com/flarum/laravel-helpers) package. These helpers should NOT be used directly in Flarum extension code; they are available so that Laravel-based libraries that expect them to exist don't malfunction. + +### Search Changes + +As part of our ongoing efforts to make Flarum's search system more flexible, we've made several refactors in beta 16. Most notably, filtering and searching are now treated as different mechanisms, and have separate pipelines and extenders. Essentially, if a query has a `filter[q]` query param, it will be treated as a search, and all other filter params will be ignored. Otherwise, it will be handled by the filtering system. This will eventually allow searches to be handled by alternative drivers (provided by extensions), such as ElasticSearch, without impacting filtering (e.g. loading recent discussions). Classes common to both systems have been moved to a `Query` namespace. + +Core's filtering and default search (named SimpleFlarumSearch) implementations are quite similar, as both are powered by the database. `List` API controllers call the `search` / `filter` methods on a resource-specific subclass of `Flarum\Search\AbstractSearcher` or `Flarum\Filter\AbstractFilterer`. Arguments are an instance of `Flarum\Query\QueryCriteria`, as well as sort, offset, and limit information. Both systems return an instance of `Flarum\Query\QueryResults`, which is effectively a wrapper around a collection of Eloquent models. + +The default systems are also somewhat similar in their implementation. `Filterer`s apply Filters (implementing `Flarum\Filter\FilterInterface`) based on query params in the form `filter[FILTER_KEY] = FILTER_VALUE` (or `filter[-FILTER_KEY] = FILTER_VALUE` for negated filters). SimpleFlarumSearch's `Searcher`s split the `filter[q]` param by spaces into "terms", apply Gambits (implementing `Flarum\Search\GambitInterface`) that match the terms, and then apply a "Fulltext Gambit" to search based on any "terms" that don't match an auxiliary gambit. Both systems then apply sorting, an offset, and a result count limit, and allow extensions to modify the query result via `searchMutators` or `filterMutators`. + +Extensions add gambits and search mutators and set fulltext gambits for `Searcher` classes via the `SimpleFlarumSearch` extender. They can add filters and filter mutators to `Filterer` classes via the `Filter` extender. + +With regards to upgrading, please note the following: + +- Search mutations registered by listening to the `Searching` events for discussions and users will be applied as to searches during the search mutation step via a temporary BC layer. They WILL NOT be applied to filters. This is a breaking change. These events have been deprecated. +- Search gambits registered by listening to the `ConfigureUserGambits` and `ConfigureDiscussionGambits` events will be applied to searcher via a temporary BC layer. They WILL NOT be applied to filters. This is a breaking change. These events have been deprecated. +- Post filters registered by listening to the `ConfigurePostsQuery` events will be applied to post filters via a temporary BC layer. That event has been deprecated. + +### Testing Library + +The `flarum/testing` package provides utils for PHPUnit-powered automated backend tests. See the [testing documentation](testing.md) for more info. + +### Optional Dependencies + +Beta 15 introduced "extension dependencies", which require any extensions listed in your extension's `composer.json`'s `require` section to be enabled before your extension can be enabled. + +With beta 16, you can specify "optional dependencies" by listing their composer package names as an array in your extension's `extra.flarum-extension.optional-dependencies`. Any enabled optional dependencies will be booted before your extension, but aren't required for your extension to be enabled. + +### Access Token and Authentication Changes + +#### Extension API changes + +The signature to various method related to authentication have been changed to take `$token` as parameter instead of `$userId`. Other changes are the result of the move from `$lifetime` to `$type` + +- `Flarum\Http\AccessToken::generate($userId)` no longer accepts `$lifetime` as a second parameter. Parameter has been kept for backward compatibility but has no effect. It will be removed in beta 17. +- `Flarum\Http\RememberAccessToken::generate($userId)` should be used to create remember access tokens. +- `Flarum\Http\DeveloperAccessToken::generate($userId)` should be used to create developer access tokens (don't expire). +- `Flarum\Http\SessionAccessToken::generate()` can be used as an alias to `Flarum\Http\AccessToken::generate()`. We might deprecate `AccessToken::generate()` in the future. +- `Flarum\Http\Rememberer::remember(ResponseInterface $response, AccessToken $token)`: passing an `AccessToken` has been deprecated. Pass an instance of `RememberAccessToken` instead. As a temporary compatibility layer, passing any other type of token will convert it into a remember token. In beta 17 the method signature will change to accept only `RememberAccessToken`. +- `Flarum\Http\Rememberer::rememberUser()` has been deprecated. Instead you should create/retrieve a token manually with `RememberAccessToken::generate()` and pass it to `Rememberer::remember()` +- `Flarum\Http\SessionAuthenticator::logIn(Session $session, $userId)` second parameter has been deprecated and is replaced with `$token`. Backward compatibility is kept. In beta 17, the second parameter method signature will change to `AccessToken $token`. +- `AccessToken::generate()` now saves the model to the database before returning it. +- `AccessToken::find($id)` or `::findOrFail($id)` can no longer be used to find a token, because the primary key was changed from `token` to `id`. Instead you can use `AccessToken::findValid($tokenString)` +- It's recommended to use `AccessToken::findValid($tokenString): AccessToken` or `AccessToken::whereValid(): Illuminate\Database\Eloquent\Builder` to find a token. This will automatically scope the request to only return valid tokens. On forums with low activity this increases the security since the automatic deletion of outdated tokens only happens every 50 requests on average. + +#### Symfony session changes + +If you are directly accessing or manipulating the Symfony session object, the following changes have been made: + +- `user_id` attribute is no longer used. `access_token` has been added as a replacement. It's a string that maps to the `token` column of the `access_tokens` database table. + +To retrieve the current user from inside a Flarum extension, the ideal solution which was already present in Flarum is to use `$request->getAttribute('actor')` which returns a `User` instance (which might be `Guest`) + +To retrieve the token instance from Flarum, you can use `Flarum\Http\AccessToken::findValid($tokenString)` + +To retrieve the user data from a non-Flarum application, you'll need to make an additional database request to retrieve the token. The user ID is present as `user_id` on the `access_tokens` table. + +#### Token creation changes + +The `lifetime` property of access tokens has been removed. Tokens are now either `session` tokens with 1h lifetime after last activity, or `session_remember` tokens with 5 years lifetime after last activity. + +The `remember` parameter that was previously available on the `POST /login` endpoint has been made available on `POST /api/token`. It doesn't return the remember cookie itself, but the token returned can be used as a remember cookie. + +The `lifetime` parameter of `POST /api/token` has been deprecated and will be removed in Flarum beta 17. Partial backward compatibility has been provided where a `lifetime` value longer than 3600 seconds is interpreted like `remember=1`. Values lower than 3600 seconds result in a normal non-remember token. + +New `developer` tokens that don't expire have been introduced, however they cannot be currently created through the REST API. Developers can create developer tokens from an extension using `Flarum\Http\DeveloperAccessToken::generate($userId)`. + +If you manually created tokens in the database from outside Flarum, the `type` column is now required and must contain `session`, `session_remember` or `developer`. Tokens of unrecognized type cannot be used to authenticate, but won't be deleted by the garbage collector either. In a future version extensions will be able to register custom access token types. + +#### Token usage changes + +A [security issue in Flarum](https://github.com/flarum/core/issues/2075) previously caused all tokens to never expire. This had limited security impact due to tokens being long unique characters. However custom integrations that saved a token in an external database for later use might find the tokens no longer working if they were not used recently. + +If you use short-lived access tokens for any purpose, take note of the expiration time of 1h. The expiration is based on the time of last usage, so it will remain valid as long as it continues to be used. + +Due to the large amount of expired tokens accumulated in the database and the fact most tokens weren't ever used more than once during the login process, we have made the choice to delete all access tokens a lifetime of 3600 seconds as part of the migration, All remaining tokens have been converted to `session_remember` tokens. + +#### Remember cookie + +The remember cookie still works like before, but a few changes have been made that could break unusual implementations. + +Now only access tokens created with `remember` option can be used as remember cookie. Any other type of token will be ignored. This means if you create a token with `POST /api/token` and then place it in the cookie manually, make sure you set `remember=1` when creating the token. + +#### Web session expiration + +In previous versions of Flarum, a session could be kept alive forever until the Symfony session files were deleted from disk. + +Now sessions are linked to access tokens. A token being deleted or expiring will automatically end the linked web session. + +A token linked to a web session will now be automatically deleted from the database when the user clicks logout. This prevents any stolen token from being re-used, but it could break custom integration that previously used a single access token in both a web session and something else. + +### Miscellaneous + +- The IP address is now available in requests via `$request->getAttribute('ipAddress')` +- Policies can now return `true` and `false` as aliases for `$this->allow()` and `$this->deny()`, respectively. +- The `user.edit` permission has been split into `user.editGroups`, `user.editCredentials` (for email, username, and password), and `user.edit` (for other attributes). +- There are now permissions (`bypassTagCounts`) that allow users to bypass tag count requirements. +- Flarum now supports PHP 7.3 - PHP 8.0, with support for PHP 7.2 officially dropped. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md new file mode 100644 index 000000000..f2debf5e5 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/update-b8.md @@ -0,0 +1,114 @@ +# Updating For Beta 8 + +All extensions will need to be refactored in order to work with beta 8. Here are the main things you will need to do in order to make your extension compatible. + +:::caution + +This guide is not comprehensive. You may encounter some changes we haven't documented. If you need help, start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## PHP Namespaces + +Beta 8 comes with large changes to the overall structure of the PHP backend. You will need to look through [this list](https://discuss.flarum.org/d/6572-help-us-namespace-changes) of namespace changes and make changes to your extension accordingly. + +[This script](https://gist.github.com/tobyzerner/55e7c05c95404e5efab3a9e43799d375) can help you to automate most of the namespace changes. Of course, you should still test your extension after running the script as it may miss something. + +## Database Naming + +Many database columns and JSON:API attributes have been renamed to conform to a [convention](/contributing.md#database). You will need to update any instances where your extension interacts with core data. You can see the changes in [#1344](https://github.com/flarum/core/pull/1344/files). + +## 扩展器 + +Beta 8 introduces a new concept called **extenders** that replace the most common event listeners. You can learn more about how they work in the [updated extension docs](start.md#extenders). + +`bootstrap.php` has been renamed to `extend.php` and returns an array of extender instances and functions: + +```php +use Flarum\Extend; + +return [ + (new Extend\Frontend('forum')) + ->js(__DIR__.'/js/dist/forum.js') + ->css(__DIR__.'/less/forum.less') + ->route('/t/{slug}', 'tag') + ->route('/tags', 'tags'), + + function (Dispatcher $events) { + $events->subscribe(Listener\AddForumTagsRelationship::class); + } +] +``` + +If you're listening for any of the following events, you'll need to update your code to use an extender instead. See the relevant docs for more information. + +| Event | Extender | +| ------------------------------------- | --------------------------- | +| `Flarum\Event\ConfigureFormatter`* | `Flarum\Extend\Formatter` | +| `Flarum\Event\ConfigureWebApp`* | `Flarum\Extend\Frontend` | +| `Flarum\Event\ConfigureClientView`* | `Flarum\Extend\Frontend` | +| `Flarum\Event\ConfigureLocales` | `Flarum\Extend\Locales` | +| `Flarum\Event\ConfigureApiRoutes` | `Flarum\Extend\Routes` | +| `Flarum\Event\ConfigureForumRoutes` | `Flarum\Extend\Routes` | + +_\* class no longer exists_ + +## JavaScript Tooling + +Previously Flarum and its extensions used a custom Gulp workflow to compile ES6 source code into something that browsers could understand. Beta 8 switches to a more conventional approach with Webpack. + +You will need to tweak the structure of your extension's `js` directory. Currently, your JS file hierarchy looks something like the following: + +``` +js +├── admin +│ ├── src +│ │ └── main.js +│ ├── dist +│ │ └── extension.js +│ ├── Gulpfile.js +│ └── package.json +└── forum + ├── src + │ └── main.js + ├── dist + │ └── extension.js + ├── Gulpfile.js + └── package.json +``` + +You'll need to make the following changes: + +1. Update `package.json` and create `webpack.config.js`, `forum.js`, and `admin.js` files using [these templates](frontend.md#transpilation). + +2. Inside your `admin` and `forum` *folders*, delete `Gulpfile.js`, `package.json`, and `dist`. Then inside each `src` folder, rename `main.js` to `index.js`. Now move all of the `src` files outside of `src` folder and delete it. + +3. In the root `js` folder create a folder called `src` and move your `admin` and `forum` *folders* into it. + +4. While still in your root `js` folder, run `npm install` and then `npm run build` to build the new JS dist files. + +If everything went right, your folder structure should look something like this: + +``` +js +├── src +│ ├── admin +│ │ └── index.js +│ └── forum +│ └── index.js +├── dist +│ ├── admin.js +│ ├── admin.js.map +│ ├── forum.js +│ └── forum.js.map +├── admin.js +├── forum.js +├── package.json +└── webpack.config.js +``` + +Take a look at the [bundled extensions](https://github.com/flarum) for more examples. + +## Font Awesome Icons + +Beta 8 upgrades to Font Awesome 5, in which icon class names have changed. The `flarum/helpers/icon` helper now requires the **full Font Awesome icon class names** to be passed, eg. `fas fa-bolt`. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/views.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/views.md new file mode 100644 index 000000000..fc4a75a86 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extend/views.md @@ -0,0 +1,63 @@ +# Views and Blade + +Although the Flarum UI you know and love is powered by our [Mithril frontend](frontend), server-side generated templates are still used throughout Flarum. Most notably, the HTML skeleton of the forum, which includes various SEO meta tags, as well as the no-js view of the forum, is implemented through the Views and Blade systems. + +[Blade](https://laravel.com/docs/8.x/blade) is Laravel's templating engine, which allows you to conveniently generate HTML (or other static content) from PHP. It's the same idea as [Jinja](https://jinja.palletsprojects.com/en/3.0.x/) or [EJS](https://ejs.co/). [Views](https://laravel.com/docs/8.x/views) are Laravel's system for organizing/registering Blade templates, and also includes utilities for rendering them and providing them with variables. + +For our purposes, views are directories containing `.blade.php` template files (possibly contained in subdirectories). + +## Adding Views + +You will need to tell the view factory where it can find your extension's view files by adding a `View` extender to `extend.php`: + +```php +use Flarum\Extend; +use Illuminate\Contracts\View\Factory; + +return [ + (new Extend\View) + ->namespace('acme.hello-world', __DIR__.'/views'), +]; +``` + + +## Blade Templates + +To learn about the syntax for Blade templates, read [Laravel's documentation](https://laravel.com/docs/8.x/blade). + +Once you've set up your views, you can render them to strings: + +```php +// Here, $view is of type `Illuminate\Contracts\View\Factory` +$renderedString = $view->make('acme.hello-world::greeting')->render(); + +// You can also pass variables to the view: +$renderedString = $view->make('acme.hello-world::greeting', ['varName' => true])->render(); +``` + +You can obtain the view factory instance through dependency injection. + +The format is `"VIEW_NAMESPACE::VIEW_NAME"`. If the view folder is organized as subdirectories, replace `/` with `.` in the pack. So if you have a file at `"forum/error.blade.php"` in a namespace called `"custom-views"`, you would use `"custom-views::forum.error"`. + +Note that all Blade templates rendered this way automatically have access to the following variables: + +- `$url`: a [URL generator](routes#generating-urls) instance. +- `$translator`: a [Translator](i18n#server-side-translation) instance. +- `$settings`: a [SettingsInterface](settings) instance. +- `$slugManager`: a [SlugManager](slugging) instance. + +Additionally, templates used by [content logic](routes#content) have access to `$forum`, which represents the [Forum API Document's attributes](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Serializer/ForumSerializer.php#L19). + +## Overriding Views + +If you want to override templates added by core or extensions, set up a view folder structure matching the one you are trying to override, containing just the files you are trying to override. Then use the `View` extender's `extendNamespace` method: + +```php +use Flarum\Extend; +use Illuminate\Contracts\View\Factory; + +return [ + (new Extend\View) + ->extendNamespace('acme.hello-world', __DIR__.'/override_views'); +]; +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extenders.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extenders.md new file mode 100644 index 000000000..68f335602 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extenders.md @@ -0,0 +1,23 @@ +# 本地扩展 + +如果您想要在没有分发整个扩展的情况下自定义您的站点, 您可以通过使用 **本地扩展** 来做到这一点。 Each Flarum installation comes with an `extend.php` file where you can add extender instances, just like in a full extension. + +See our [extension documentation](extend/start.md) for more information about extenders (and even an [example of a local extender](extend/start.md#hello-world)). + +If you need to create new files (when adding a custom class to be imported for extenders), you'll need to adjust your composer.json a bit. Add the following: + +```json +"autoload": { + "psr-4": { + "App\\": "app/" + } +}, +``` + +Now you can create new PHP files in an `app` subdirectory using the `App\...` namespace. + +:::tip Local Extenders vs Extensions + +Local extenders can be good for small tweaks, but if you need large customizations, an extension might be a better choice: a separate codebase, cleaner handling of many files, developer tooling, and the ability to easily open source are big benefits. + +::: diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extensions.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extensions.md new file mode 100644 index 000000000..e313c9549 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/extensions.md @@ -0,0 +1,118 @@ +# 扩展程序 + +Flarum 是简约的,同时也是高度可扩展的。 实际上,Flarum 附带的大部分功能都是扩展程序。 + +这种方法使得 Flarum 具有极高的可定制性。 您可以禁用任何您不需要的功能,并安装其他扩展,打造更适合您的社区。 + +如果您想了解更多关于 Flarum 的理念,我们在核心中包含了哪些功能,或者您想制作自己的扩展,请查看我们的 [扩展文档](extend/README.md)。 本文将重点讨论从论坛管理员的角度管理扩展。 + +## Extension Manager + +The extension manager is an extension that comes bundled with Flarum when installed via an archive. It provides a graphical interface for installing and updating both extensions and Flarum itself. + +If you do not have the extension manager installed and you wish to install it, you can do so by running the following command in your Flarum directory: + +```bash +composer require flarum/extension-manager:"*" +``` + +:::warning + +The extension manager allows an admin user to install any composer package. Only install the extension manager if you trust all of your forum admins with such permissions. + +::: + +![extension manager admin page](https://github.com/flarum/docs/assets/20267363/d0e1f7a5-e194-4acd-af63-7b8ddd95c26b) + + +## 寻找扩展 + +Flarum 有一个广泛的扩展生态系统,其中大部分是开源和免费的。 要想找到新的超棒的扩展,请访问 Flarum 社区论坛上的 [扩展](https://discuss.flarum.org/t/extensions) 标签。 非官方的 [Extiverse 扩展数据库](https://extiverse.com/) 也是一个好地方。 + +## 安装扩展 + +### Through the interface + +Using the extension manager extension, you can install extensions directly from the admin dashboard. Once you have browsed the list of available extensions from the links above, and found one you want to install, you can install it by entering the extension's composer package name into the extension manager's installation input. + +![Installing an extension](/en/img/install-extension.png) + +### Through the command line + +与 Flarum 一样,扩展是使用 SSH 通过 [Composer](https://getcomposer.org) 安装的。 要安装一个典型的扩展: + +1. `cd` to your Flarum directory. `cd` 到 `composer.json` 所在文件夹。 您可以通过 `ls -la` 查看目录下的文件。 +2. 运行 `composer require COMPOSER_PACKAGE_NAME:*`. 具体安装命令一般可在扩展的文档中找到。 + +## 管理扩展 + +### Through the interface + +Using the extension manager extension, you can update extensions directly from the admin dashboard. You can run a check for updates by clicking the "Check for updates" button in the extension manager. If there are updates available, you can update all extensions by clicking the "Global update" button. Or, you can update individual extensions by clicking the "Update" button next to the extension you want to update. + +![Updating an extension](/en/img/update-extension.png) + +### Through the command line + +按照扩展开发者提供的说明操作。 如果你使用 `*` 作为扩展的版本字符串([如推荐所示](composer.md)),运行[Flarum升级指南](update.md)中列出的命令应该会更新你的所有扩展。 + +## 卸载扩展 + +### Through the interface + +Using the extension manager extension, you can uninstall extensions directly from the admin dashboard. You can uninstall an extension by clicking the "Uninstall" button next to the extension you want to uninstall inside the extension's page. + +![Uninstalling an extension](/en/img/uninstall-extension.png) + +### Through the command line + +类似安装的步骤,若要移除扩展: + +0. 如果你想移除由扩展创建的所有数据库表,请在管理员仪表板中点击"重置"按钮。 更多信息[见下](#managing-extensions)。 +1. `cd` to your Flarum directory. +2. 运行 `composer require COMPOSER_包名`。 具体安装命令一般可在扩展的文档中找到。 + +## 管理扩展 + +Each individual extension page of the admin dashboard provides a convenient way to manage the extension. 您可以: + +- Enable or disable the extension. +- See the settings provided by the extension, and change them. +- 回滚一个扩展的迁移,以删除它所做的任何数据库修改(这可以通过重置按钮来完成)。 这将删除与该扩展相关的所有数据,并且是不可逆的。 只有当你要删除一个扩展程序,并且不打算再次安装它时,才应该这样做。 当然这不是非要做的事情,选择权在您手中。 +- See the extension's README, if it has one. +- See the extension's version. +- Uninstall the extension if the extension manager is installed. + +## Configuring additional extension repository sources + +The extension manager uses `composer` under the hood, and as such, it looks for extension packages in the same places as `composer`. By default, this is [Packagist](https://packagist.org/). However, you can configure additional sources for the extension manager to look for extensions in. This is useful if you want to install an extension that is not available on Packagist. + +In the admin page of the extension manager, clicking the **Add Repository** button will open a modal where you can enter the name and URL of the repository you want to add. The name is just a label for the repository, and can be anything you want. The URL should be the URL of the repository which depends on the type of repository you want to add. + +### Adding a repository from a VCS + +If you want to add a repository from a VCS (e.g. GitHub, GitLab, BitBucket, etc), the URL should be the URL of the repository's VCS. For example, if you had a private GitHub repository at `https://github.com/acme/flarum-extension`, you would enter that URL into the URL field. If it is a private source, you will need to enter an authentication method through the **New authentication method** button. The token can be generated from your VCS provider's website, and the host should be the domain of the VCS provider (e.g. `github.com`). + +### Adding a composer repository + +Extiverse provides access to premium extensions. It is a good example of a composer repository. You would specify the URL as `https://flarum.org/composer/` and the name as `premium`. You would also need to enter an authentication method through the **New authentication method** button. The token can be generated from your Flarum account's [subscriptions](https://flarum.org/dashboard/subscriptions) page with the Instructions button. + +* Type: `HTTP Bearer` +* Host: `flarum.org` + +![Configure repositories](/en/img/config-repositories.png) + +:::info + +The configured repositories and auth methods will be active for both the command line and the admin dashboard. If you configure them from the command line however, you must not include the flag `--global`. + +::: + +## Installing Non-stable extensions + +If for whatever reason you want to install a non-stable extension (e.g. a beta, alpha or RC version) you must first update the **Minimum stability** setting to the wanted stability. + +* If you set it to Alpha, you will be able to install alpha, beta, RC (Release Candidate) and stable versions. +* If you set it to Beta, you will be able to install beta, RC and stable versions. +* If you set it to RC, you will be able to install RC and stable versions. +* If you set it to Stable, you will only be able to install stable versions. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/faq.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/faq.md new file mode 100644 index 000000000..248cfeea8 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/faq.md @@ -0,0 +1,35 @@ +# 常见问题 + +### Flarum 现在是正式版吗? + +是的! 经过 6 年的开发之后,Flarum 1.0.0 最终来了。 + +### 展望未来,下一阶段 Flarum 会做些什么? + +相应的计划还在制定中。 不过我们已经有了很多很多想法,期待届时在社区中分享给大家。 + +### 我可以捐款以加快开发进展吗? + +衷心感谢所有的捐款。 您可以在 [Github Sponsors](https://github.com/sponsors/flarum) 或 [OpenCollective](https://opencollective.com/flarum) 上捐款。 + +但是,捐款并不会直接影响 Flarum 的开发速度。 我们也鼓励用户在其他方面做出贡献,比如 [贡献代码](contributing.md)、[开发扩展](/extend/)、编写文档、将 Flarum 翻译成其他语言,或在 [社区论坛](https://discuss.flarum.org/) 上提供帮助和支持,成为社区里的中坚力量! + +### Flarum 会有****的功能吗? 什么时候有? 为什么还没做呢? + +我们很想让 Flarum 的功能和插件应有尽有、一应俱全,但现阶段,基本功能和稳定性才是重点。 + +### 我可以将 Flarum 与 WordPress/Laravel/等等集成吗? + +同样,答案是「要事先为」。 如果我们还没有解决一个 Issue(或给它分配了一个里程碑),那是因为我们正在处理其他同样重要的事情,所以请耐心等待。 我们会尽量在新版本发布前搞定它。 如果您很着急,可以自行修复它 [并为项目做出贡献](contributing.md)! + +### 我可以将我的论坛迁移到 Flarum 上吗? + +我们目前没有提供官方的迁移工具,但是现在已有很多由社区提供的解决办法。 一旦我们有信心 Flarum 可以用于生产环境,我们将打造从其他论坛软件(例如 esoTalk、FluxBB、phpBB、Discourse等)导入数据的工具。 + +### 我如何加入 Flarum 团队? + +> “通过一个神秘而艰苦的考验,这涉及了神秘的仪式,危机生命的冒险,以及对有去无回的远方世界的探索。” ~ jordanjay29 + +好了,认真地说,我们一般都会留意社区里出类拔萃的成员,他们或许能够成为优秀的员工。 就拿我们目前的多数员工来说,他们现在做的事情与成为正式员工前没有什么两样。 + +因此,找到属于您的激情,并以您觉得最好的方式做出贡献。 然后顺其自然。 在这,没有勋章也能让您受到尊重。 \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/install.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/install.md new file mode 100644 index 000000000..6fc0937c7 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/install.md @@ -0,0 +1,198 @@ +# 安装 + +:::tip 即刻测试 Flarum? + +欢迎前往我们的 [演示站点](https://discuss.flarum.org/d/21101) 试用 Flarum。 您也可以用几秒钟在 [Free Flarum](https://www.freeflarum.com)(一个免费的非官方社区托管服务)建立属于您自己的论坛。 + +::: + +## 环境要求 + +在您安装 Flarum 之前,请确保您的服务器满足以下要求, 以便顺利的安装和运行 Flarum: + +* **Apache**(需要启用 mod\_rewrite 重写模块) 或 **Nginx** +* **PHP 7.3+** 以及以下扩展:curl、dom、fileinfo、gd、json、mbstring、openssl、pdo_mysql、tokenizer、zip +* **MySQL 5.6+** 或 **MariaDB 10.0.5+** +* **SSH (命令行) 访问权限**来运行潜在必要的软件维护命令和 Composer (如果您打算使用命令行来安装和管理 Flarum 扩展) + +## 开始安装 + +### 通过解压缩归档进行安装 + +如果您没有服务器的 SSH 访问权限,或您不想使用命令行,您可以通过解压缩来安装 Flarum。 下面是可用的归档列表,请确保与您的 PHP 版本以及 public 路径偏好 (即是否有 public 路径) 相符。 + +| Flarum 版本 | PHP 版本 | Public 路径 | 格式 | 归档 | +| --------- | ---------- | --------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1.x | 8.3 (推荐) | 无 | ZIP | [flarum-v1.x-no-public-dir-php8.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.3.zip) | +| 1.x | 8.3 (推荐) | 有 | TAR.GZ | [flarum-v1.x-php8.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.3.tar.gz) | +| 1.x | 8.3 (推荐) | 无 | TAR.GZ | [flarum-v1.x-no-public-dir-php8.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.3.tar.gz) | +| 1.x | 8.3 (推荐) | 有 | ZIP | [flarum-v1.x-php8.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.3.zip) | +| 1.x | 8.2 (推荐) | 无 | TAR.GZ | [flarum-v1.x-no-public-dir-php8.2.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.2.tar.gz) | +| 1.x | 8.2 (推荐) | 有 | TAR.GZ | [flarum-v1.x-php8.2.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.2.tar.gz) | +| 1.x | 8.2 (推荐) | 无 | ZIP | [flarum-v1.x-no-public-dir-php8.2.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.2.zip) | +| 1.x | 8.2 (推荐) | 有 | ZIP | [flarum-v1.x-php8.2.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.2.zip) | +| 1.x | 8.1 | 无 | TAR.GZ | [flarum-v1.x-no-public-dir-php8.1.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.1.tar.gz) | +| 1.x | 8.1 | 有 | TAR.GZ | [flarum-v1.x-php8.1.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.1.tar.gz) | +| 1.x | 8.1 | 无 | ZIP | [flarum-v1.x-no-public-dir-php8.1.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.1.zip) | +| 1.x | 8.1 | 有 | ZIP | [flarum-v1.x-php8.1.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.1.zip) | +| 1.x | 8.0 (结束支持) | 无 | TAR.GZ | [flarum-v1.x-no-public-dir-php8.0.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.0.tar.gz) | +| 1.x | 8.0 (结束支持) | 有 | TAR.GZ | [flarum-v1.x-php8.0.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.0.tar.gz) | +| 1.x | 8.0 (结束支持) | 无 | ZIP | [flarum-v1.x-no-public-dir-php8.0.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.0.zip) | +| 1.x | 8.0 (结束支持) | 有 | ZIP | [flarum-v1.x-php8.0.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.0.zip) | +| 1.x | 7.4 (结束支持) | 无 | TAR.GZ | [flarum-v1.x-no-public-dir-php7.4.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.4.tar.gz) | +| 1.x | 7.4 (结束支持) | 有 | TAR.GZ | [flarum-v1.x-php7.4.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.4.tar.gz) | +| 1.x | 7.4 (结束支持) | 无 | ZIP | [flarum-v1.x-no-public-dir-php7.4.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.4.zip) | +| 1.x | 7.4 (结束支持) | 有 | ZIP | [flarum-v1.x-php7.4.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.4.zip) | +| 1.x | 7.3 (结束支持) | 无 | TAR.GZ | [flarum-v1.x-no-public-dir-php7.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.3.tar.gz) | +| 1.x | 7.3 (结束支持) | 有 | TAR.GZ | [flarum-v1.x-php7.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.3.tar.gz) | +| 1.x | 7.3 (结束支持) | 无 | ZIP | [flarum-v1.x-no-public-dir-php7.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.3.zip) | +| 1.x | 7.3 (结束支持) | 有 | ZIP | [flarum-v1.x-php7.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.3.zip) | + +### 使用命令行安装 + +Flarum 使用 [Composer](https://getcomposer.org) 来管理其依赖包和扩展程序。 在安装 Flarum 之前,您需要先在机器上 [安装 Composer](https://getcomposer.org)。 然后,在要安装 Flarum 的空白目录下执行此命令: + +```bash +composer create-project flarum/flarum . +``` + +您可以在命令执行期间配置您的 Web 服务器。 请确保网站根目录(Webroot)设置为 `//public`,并按照下面的说明设置 [URL 重写](#url-rewriting)。 + +当一切就绪后,在浏览器中访问您的论坛网址,根据安装向导完成安装。 + +如果您还想从管理面板安装和升级扩展程序,您还需要安装[扩展程序管理器](extensions.md)扩展。 + +```bash +composer require flarum/extension-manager:* +``` + +:::warning + +The extension manager allows an admin user to install any composer package. Only install the extension manager if you trust all of your forum admins with such permissions. + +::: + +## URL 重写 + +### Apache + +Flarum 在 `public` 目录中附带了一个 `.htaccess` 文件,请确保它有正确生成。 **如果没有启用 `mod_rewrite` 模块,或禁用了 `.htaccess`,Flarum 将无法正常运行。 ** 请确认您的主机提供商(或您的 VPS)是否启用了这些功能。 如果您的服务器由您自行管理,您可能需要在您的网站配置中添加以下内容来启用 `.htaccess` 文件: + +``` + + AllowOverride All + +``` + +以上确保了覆盖 htaccess 是被允许的,因此 Flarum 可以正确地重写 URL。 + +启用 `mod_rewrite` 的方法会因操作系统的不同而不同。 在 Ubuntu 上,您可以通过运行 `sudo a2enmod rewrite` 命令来启用它。 而在 CentOS 上 `mod_rewrite` 是默认启用的。 请不要忘记在修改配置后重启 Apache! + +### Nginx + +Flarum 根目录附带了一个 `.nginx.conf` 文件,请确保它有正确生成。 假如您已经在 Nginx 中建立了一个 PHP 站点,您应当在站点配置中添加以下内容,以导入默认的重写规则: + +```nginx +include //.nginx.conf; +``` + +### Caddy + +Caddy 的配置很简单。 您需要将下方代码中的 URL 替换为自己的 URL,并将 path 替换为自己的 `public` 文件夹路径。 如果您使用的是其他版本的 PHP,您还需要修改 `fastcgi` 路径,使其指向正确的 PHP 安装 Socket 或 URL 。 + +``` +www.example.com { + root * /var/www/flarum/public + php_fastcgi unix//var/run/php/php7.4-fpm.sock + header /assets/* { + +Cache-Control "public, must-revalidate, proxy-revalidate" + +Cache-Control "max-age=25000" + Pragma "public" + } + file_server +} +``` +## 目录所有权 + +在安装过程中,Flarum 可能会要求您将某些目录设置为可写。 现代操作系统通常是多用户的,意味着您所登录的用户与Flarum所运行在的用户不同。 Flarum所运行在的用户必须拥有以下文件的读+写权限: + +- 根安装目录,以便Flarum 编辑 `config.php`。 +- `storage` 子目录,以便Flarum 编辑日志并存储缓存数据。 +- `assets` 子目录,以便Logo和头像可以被上传到文件系统。 + +扩展程序可能需要其它目录,所以你可能需要递归地授予整个Flarum 根安装目录的写权限。 + +您需要运行几个命令来设置文件权限。 请注意,如果您在执行一部分安装后没有显示警告,您无需运行其余部分。 + +首先,您需要允许写访问目录。 在 Linux 上: + +```bash +chmod 775 -R /path/to/directory +``` + +如果这还不够,您可能需要检查您的文件所属者是否为正确的群组和用户。 大多数 Linux 发行版,默认 `www-data` 为 PHP 和 Web 服务器所有者和所属组群。 您需要查看您的 distro 和 web 服务器设置的具体细节才能做出确定。 您可以运行下面这条命令来改变大多数 Linux 操作系统中文件夹的所有者。 + +```bash +chown -R www-data:www-data /path/to/directory +``` + +如果您的网页服务器使用了不同的用户/群组,请将 `www-data` 更改为对应的内容。 + +此外,您还需要确保您登录终端的 CLI 用户拥有所有权,这样您就可以通过 CLI 安装扩展并管理 Flarum 安装。 要执行此操作,请使用 `usermod -a -G www-data YOUR_USERNAME` 将当前用户(`whoami`)添加到 web 服务器组(通常为`www-data`)。 您可能需要注销并重新登录才能使此更改生效。 + +最后,如果这不起作用,您可能需要配置 [SELinux](https://www.redhat.com/en/topics/linux/what-is-selinux) 以允许 Web 服务器写入目录。 要执行此操作,请运行: + +```bash +chcon -R -t httpd_sys_rw_content_t /path/to/directory +``` + +要了解有关这些命令以及 Linux 上的文件权限和所有权的更多信息,请阅读 [本教程](https://www.thegeekdiary.com/understanding-basic-file-permissions-and-ownership-in-linux/)。 如果您在 Windows 上设置 Flarum,您可能会发现 [此Super User中的问题](https://superuser.com/questions/106181/equivalent-of-chmod-to-change-file-permissions-in-windows) 的答案有用。 + +:::caution 环境可能不同 + +您的环境可能与提供的文档不同,因此请咨询您的 Web 服务器配置或 Web 托管提供商,了解 PHP 和 Web 服务器运行所需的适当用户和组。 + +::: + +:::danger 永远不要使用 777 权限! + +您永远不应将任何文件夹或文件设置为 `777` 权限,因为此权限级别允许任何人访问文件夹和文件的内容,而无论是哪个用户或组。 + +::: + +## 自定义路径 + +默认情况下,Flarum 的目录结构包含一个 `public` 目录,其中仅包含公开可访问的文件。 这是保证安全的最佳做法,可确保所有敏感代码文件完全不能通过 Web 根路径访问。 + +但是,如果您希望在子目录中托管 Flarum(例如 `yoursite.com/forum`),或者如果您的主机没有让您控制 Web 根目录(只能使用 `public_html` 或 `htdocs` 之类的目录),您可以在没有 `public` 目录的情况下设置 Flarum。 + +如果您打算使用其中一个档案安装 Flarum, 您可以使用 `no-public-dir` (Public 路径=无) [归档](#installing-by-unpacking-an-archive)并跳过本节其余部分。 如果您正在通过 Composer 安装,您需要遵循下面的说明。 + +这种情况下,您需要将 `public` 目录中的所有文件(包括 `.htaccess`)全部移动到要安装 Flarum 的目录中。 然后编辑 `.htaccess` 并取消注释用来保护敏感文件的第 9-15 行代码。 如果是 Nginx,则取消注释 `.nginx.conf` 文件的第 8-11 行。 + +然后编辑 `index.php` 文件,修改这一行: + +```php +$site = require './site.php'; +``` + + 最后,编辑 `site.php` 并更新以下行所指的路径,以翻译新的目录结构: + +```php +'base' => __DIR__, +'public' => __DIR__, +'storage' => __DIR__.'/storage', +``` + +最后,检查 `config.php`,确保 `url` 值是正确的。 + +## 导入数据 + +如果您想用 Flarum 接续运营现有的一个社区,您可以将该论坛的数据导入到 Flarum 中。 虽然目前还没有官方的导入工具,但是社区里已经有人制作了几款非官方的导入工具: + +* [FluxBB](https://discuss.flarum.org/d/3867-fluxbb-to-flarum-migration-tool) +* [MyBB](https://discuss.flarum.org/d/5506-mybb-migrate-script) +* [phpBB](https://discuss.flarum.org/d/1117-phpbb-migrate-script-updated-for-beta-5) +* [SMF2](https://github.com/ItalianSpaceAstronauticsAssociation/smf2_to_flarum) + +这些导入器还可以用于其他论坛软件,方法是首先将它们迁移到phpBB,然后再迁移到Flarum。 需要说明的是,我们不能保证这些工具一直能正常使用,也不能为他们提供支持服务。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/README.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/README.md new file mode 100644 index 000000000..e70ba1590 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/README.md @@ -0,0 +1,7 @@ +--- +slug: '/internal' +--- + +# 团队内部文档 + +这是一个全新的部分,我们将在这里发布一些 Flarum 团队内部使用的文档。 我们开始此部分以向我们的社区提供有关 Flarum 如何运作的透明度,与帮助想要为 Flarum 贡献的人们。 \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md new file mode 100644 index 000000000..2b300deec --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/bundled-extensions-policy.md @@ -0,0 +1,28 @@ +# 捆绑扩展策略 + +本文件旨在协助确定“Flarum”项目小组应将哪些核心特征捆绑起来或加以维护。 + +认识到Flarum的目的是要有一个精干和高效的团队。 To guarantee a transparent workload, we intentionally have a "this could be an extension" mentality. The acronym D.O.R.C. spells out our decision-making process. + +- **Density**: prevent bloating Flarum so that it becomes a burden to install on shared hosting plans with limited space. +- **Opinionatedness**: no extensions should be bundled that is only useful by only a limited amount of communities or on specific hosting environments. +- **Responsibility**: extensions that could easily be maintained by others should be maintained by others. +- **Complexity**: extensions that are complex in terms of design, frontend or backend code should not be a responsibility of the Flarum project team. + +### Density + +To prevent the installation size of Flarum from continuously increasing we need to protect it from extensions that bloat it. We should ship extensions with Flarum that, for instance, have kilobytes in media files. + +### Opinionatedness + +Our goal is to allow installation of Flarum, in its vanilla form, by any community on any hosting environment. This includes shared hosting environment as well. + +Releasing Flarum with extensions that add functionality specific to cloud based (AWS) installations or for corporate support communities, as such, is unwanted. + +### Responsibility + +Protecting the time of the project team is key. To do so we should empower the ecosystem in building extensions that it needs. Therefor we distance ourselves from the responsibility of building every and all extensions. The responsibility of extension development is held primarily by our community. + +### Complexity + +Complex extensions require a vast amount of time, not just for development, but also documentation and support. To protect the lean and efficient principles of the team, we will not take ownership of extensions that add this complexity. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md new file mode 100644 index 000000000..c6ef1c890 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/extension-manager.md @@ -0,0 +1,87 @@ +# Extension Manager +This contains an explanation of how the extension manager works and what it has to offer. + +slightly outdated: see [the extensions guide for more](/extensions.md). + +## Contents +* Installing, Updating, and Removing Extensions. +* [Checking for Updates](#checking-for-updates). +* [Global Flarum Update](#global-flarum-updates). +* [Patch-Minor Flarum Updates](#patch-minor-flarum-updates). +* [Major Flarum Update](#major-flarum-updates). +* [Flarum Updates (global, minor, major)](#flarum-updates-global-minor-major). +* [Background Tasks](#background-tasks). + +## Requirements +There are some obstacles that need to be taken care of before this can be used. + +### File Permissions +The relevant machine web user needs to have permissions to read and write to: `vendor`, `composer.json`, `composer.lock` and `storage`. Right now a warning shows up when this is not the case, this should preferably be changed to mention only the files/dirs where permissions are lacking instead of all of them. + +![flarum lan_admin (3)](https://user-images.githubusercontent.com/20267363/135268536-f79d42ab-6e05-4e41-b2ab-d95ec7a8b021.png) + +### Path Repository +In development environments (and production in rare scenarios) there should a path repository to a directory containing (mostly dev) packages, the path to this directory must be changed to an absolute path otherwise composer will have trouble running any command. Additionally the path repository by default has higher priority, so requiring an extension that exists in that repository will probably fail, unless a `*@dev` constraint is specified, in which case the extension manager should not be used for dev purposes anyway. + +There is currently now hint of any of this in the extension manager UI. + +## Common Actions +Each one of the features listed above is basically a composer command or two, and there are common actions/common behaviour between them all. + +* Restricting access to the admin. +* Validating the provided package name or the extension id if given. +* Erroring out if installing an existing extension, updating or removing a non existing extension ...etc +* Running the command. This [auto logs the output](#command-output-logging). +* [Erroring out on command failure](#command-failure). +* Dispatching an event. +* If running an update: + + Clear Cache. + + Run Migrations. + + Publish Assets. + + Run an update check, and log any extensions that didn't update to their latest versions in the update process. + +### Command Output Logging +Considering this is still experimental and especially for the sake of easier support, each command output is logged to `storage/logs/composer` just like the flarum error logs, allowing to go back and see what happened during a command execution. + +### Command Failure +When a composer command fails (recognised by the exit code), an exception is thrown containing a reason guessed by the exception based on the command output text. Guessed causes render into proper explanatory alert messages on the frontend. + +## Checking for Updates +This executes the command `composer outdated -D --format json` which checks for updates of packages directly required in the root `composer.json` and outputs the results in JSON format. Only packages marked as `semver-safe-update` and `update-possible` by composer are displayed. + +The information about the last update check is saved into a JSON setting. + +![flarum lan_admin (4)](https://user-images.githubusercontent.com/20267363/135272032-9de37599-b364-4e42-b234-1113135eaa83.png) + +## Global Flarum Updates +Simply runs the command `command update --prefer-dist --no-dev -a --with-all-dependencies`, useful for updating all packages. + +## Patch-Minor Flarum Updates +This changes directly required package versions to `*` and then executes the command `command update --prefer-dist --no-dev -a --with-all-dependencies`. + +![flarum lan_admin (5)](https://user-images.githubusercontent.com/20267363/135276114-ae438c2f-4122-45bd-b32f-690de3b56e25.png) + +## Major Flarum Updates +This changes directly required package versions to `*`, changes core to the latest major version requirement and then executes the same command above. Upon failure, it can be correctly guessed that some extensions are not compatible with the new major version, the exception details will include an array of extension package names that are not compatible, and it'll be rendered in the frontend, with the ability to run a `composer why-not flarum/core 2.0` for more details. + +![major update UI](https://user-images.githubusercontent.com/20267363/143277865-8323fa9a-c80f-4015-baca-fce4d2b5d585.png) + +## Flarum Updates (global, minor, major) +Information about the last updates ran are saved in a `last_update_run` JSON setting, which can contain an array of extension package names that didn't update to their latest version in the process, this is rendered in the frontend as warning icon buttons on the extension items, clicking on them will execute a `composer why-not`, displaying the details of the failure in a modal. + +![UI with list of extensions containing warning icon buttons](https://user-images.githubusercontent.com/20267363/143278774-6fada0da-dead-474b-8dfa-feda5021134f.png) ![UI with the modal showing the details](https://user-images.githubusercontent.com/20267363/143278786-d283db62-de96-4019-954e-932d0d6eac15.png) + +## Background Tasks +To get around timeout issues, composer commands can also run on the background use the queue. Users can be pointed towards [Blomstra's Database Queue Implementation](https://discuss.flarum.org/d/28151-database-queue-the-simplest-queue-even-for-shared-hosting) as a basic queue solution. It contains instructions on how to enable the queue through a cron job. + +:::danger Cron Job PHP Process Version + +It is common for shared hosts to have a low php version used in SSH, users must be pointed to the fact that they have to make sure the php process is of a version compatible with Flarum. Either by manually checking or by asking their hosts. + +::: + +![Extension Manager Queue Table Preview](/en/img/extension-manager-queue.png) + +## TODO +- Try on shared hosting. +- Better explanation on the UI about background tasks. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md new file mode 100644 index 000000000..c869da242 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/merging-policy.md @@ -0,0 +1,38 @@ +# PR 合并方针 + +对 Flarum 源代码的技术性贡献需要经过审查流程。 多年来,我们依据我们的经验、我们目标明确的开发速度和可得性来调整这一流程。 + +## 什么造就了优秀的 Pull Request? + +优秀的 Pull Requests: + +- 在发起 pull request 时,完整填写 [Pull Request 模板](https://github.com/flarum/.github/blob/main/PULL_REQUEST_TEMPLATE.md)。 +- 不合并不同的更改。 不要修改无关代码的格式,即使它很有吸引力。 专注于你想贡献的单一功能或变更。 +- 有一个相关的已被核心团队认可的技术实行方案的 issue,或者该技术实行方案已经被核心团队通过官方论坛的讨论或类似于 Discord 的其他渠道同意。 +- 清楚地解释此更改的必要性并列出此 pull request 需要讨论的地方。 + +## 执行审查标准 + +- 遵循我们的公约或者可以轻松地在合并后修补,遵循适当的代码风格。 +- 是否有任何实行细节可以通过替代技术/技术办法做得更好? +- 不触及预定更改之外的任何行,例如通过格式化或编译。 +- 如果修改了公共 API 代码,是否有适当的文档部分? + +## 合并时间! + +如果符合所有模板中的检查,**任何**核心开发者都可以合并这个 PR。 如果此 PR 由一名核心开发者编写,他们可能是合并它的人。 + +- 合并: + - GitHub 提供了合并 PR 的几种方式。 在以下策略中选择: + - 当 PR 分支由单个的描述细致的提交组成,并且适合出现在版本列表中,选择 **Merge**。 + - 当积攒了大量提交时,**Squash** 是个好选择。 请务必按照 [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) 规范来 squash 提交。 我们通常会在这些预制的提交信息中发现一些来自StyleCI等机器人的提交,他们的提交信息应该被删除。 + +- 在合并之后: + - 将相关的 issue(如果没有,则是 pull request 本身,但绝不是两者同时)分配给适当的里程碑。 + - 关闭所有相关 issue(它们*是否*被全部关闭)。 + - 回归应按此标明,并在合并后从项目板和里程碑中删除。 + - 检查后续任务: + - 合并相关的 PR(语言文件、扩展、文档)。 + - 更新文档。 + - 如有必要,为进一步的后续任务创建一个 issue。 + diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/merging.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/merging.md new file mode 100644 index 000000000..fc84821c5 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/merging.md @@ -0,0 +1,29 @@ +# PR 合并工作流程 + + +## 执行审查标准 + +- Adheres to our conventions or can be patched up easily after merging, follows proper code style. +- Are there any implementation details that could be done better through alternate technologies/technical approaches? +- Does not touch any lines outside of the intended changes, eg through formatting or compilation. +- If the changes are to code intended as a public API, has a proper doc block been included? + +## Merge Time! + +If all of the checks in the template are met, **any** core developer may merge this PR. If the PR is authored by a core developer, they should probably be the ones to merge it. + +- 合并: + - GitHub offers several ways to merge a PR. Choose between the following strategies: + - **Merge** when the PR branch consists of atomic, well-described commits that are nice to have in the version history. + - **Squash** when lots of cleanup commits have accumulated. Please make sure to follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) spec for the squash commit. + +- 合并后: + - Make sure the *issue* (if none exists, the PR - but not both) belongs to the appropriate milestone and project board. + - PRs in extensions cannot be assigned to core milestones, so create a core issue that references it and add it to the milestone. + - Close all relevant issues (*if* they are closed completely). + - Regressions should be labeled as such and removed from the project board and milestone after merging. + - Check for follow-up tasks: + - Merge related PRs (language files, extensions, documentations). + - Documentation updates. + - Create issues for further follow-up tasks, if necessary. + diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md new file mode 100644 index 000000000..823599db5 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/internal/package-manager.md @@ -0,0 +1,89 @@ +# Package Manager +This contains an explanation of how the package manager works and what it has to offer. + +## Contents +* Installing, Updating, and Removing Extensions. +* [Checking for Updates](#checking-for-updates). +* [Global Flarum Update](#global-flarum-updates). +* [Patch-Minor Flarum Updates](#patch-minor-flarum-updates). +* [Major Flarum Update](#major-flarum-updates). +* [Flarum Updates (global, minor, major)](#flarum-updates-global-minor-major). +* [Background Tasks](#background-tasks). + +## Requirements +There are some obstacles that need to be taken care of before this can be used. + +### File Permissions +The relevant machine web user needs to have permissions to read and write to: `vendor`, `composer.json`, `composer.lock` and `storage`. Right now a warning shows up when this is not the case, this should preferably be changed to mention only the files/dirs where permissions are lacking instead of all of them. + +![flarum lan_admin (3)](https://user-images.githubusercontent.com/20267363/135268536-f79d42ab-6e05-4e41-b2ab-d95ec7a8b021.png) + +### Path Repository +In development environments (and production in rare scenarios) there should a path repository to a directory containing (mostly dev) packages, the path to this directory must be changed to an absolute path otherwise composer will have trouble running any command. Additionally the path repository by default has higher priority, so requiring an extension that exists in that repository will probably fail, unless a `*@dev` constraint is specified, in which case the package manager should not be used for dev purposes anyway. + +There is currently now hint of any of this in the package manager UI. + +## Common Actions +Each one of the features listed above is basically a composer command or two, and there are common actions/common behaviour between them all. + +* Restricting access to the admin. +* Validating the provided package name or the extension id if given. +* Erroring out if installing an existing extension, updating or removing a non existing extension ...etc +* Running the command. This [auto logs the output](#command-output-logging). +* [Erroring out on command failure](#command-failure). +* Dispatching an event. +* If running an update: + + Clear Cache. + + Run Migrations. + + Publish Assets. + + Run an update check, and log any extensions that didn't update to their latest versions in the update process. + +### Command Output Logging +Considering this is still experimental and especially for the sake of easier support, each command output is logged to `storage/logs/composer` just like the flarum error logs, allowing to go back and see what happened during a command execution. + +### Command Failure +When a composer command fails (recognised by the exit code), an exception is thrown containing a reason guessed by the exception based on the command output text. Guessed causes render into proper explanatory alert messages on the frontend. + +## Checking for Updates +This executes the command `composer outdated -D --format json` which checks for updates of packages directly required in the root `composer.json` and outputs the results in JSON format. Only packages marked as `semver-safe-update` and `update-possible` by composer are displayed. + +The information about the last update check is saved into a JSON setting. + +![flarum lan_admin (4)](https://user-images.githubusercontent.com/20267363/135272032-9de37599-b364-4e42-b234-1113135eaa83.png) + +## Global Flarum Updates +Simply runs the command `command update --prefer-dist --no-dev -a --with-all-dependencies`, useful for updating all packages. + +## Patch-Minor Flarum Updates +This changes directly required package versions to `*` and then executes the command `command update --prefer-dist --no-dev -a --with-all-dependencies`. + +![flarum lan_admin (5)](https://user-images.githubusercontent.com/20267363/135276114-ae438c2f-4122-45bd-b32f-690de3b56e25.png) + +## Major Flarum Updates +This changes directly required package versions to `*`, changes core to the latest major version requirement and then executes the same command above. Upon failure, it can be correctly guessed that some extensions are not compatible with the new major version, the exception details will include an array of extension package names that are not compatible, and it'll be rendered in the frontend, with the ability to run a `composer why-not flarum/core 2.0` for more details. + +![major update UI](https://user-images.githubusercontent.com/20267363/143277865-8323fa9a-c80f-4015-baca-fce4d2b5d585.png) + +## Flarum Updates (global, minor, major) +Information about the last updates ran are saved in a `last_update_run` JSON setting, which can contain an array of extension package names that didn't update to their latest version in the process, this is rendered in the frontend as warning icon buttons on the extension items, clicking on them will execute a `composer why-not`, displaying the details of the failure in a modal. + +![UI with list of extensions containing warning icon buttons](https://user-images.githubusercontent.com/20267363/143278774-6fada0da-dead-474b-8dfa-feda5021134f.png) ![UI with the modal showing the details](https://user-images.githubusercontent.com/20267363/143278786-d283db62-de96-4019-954e-932d0d6eac15.png) + +## Background Tasks +To get around timeout issues, composer commands can also run on the background use the queue. Users can be pointed towards [Blomstra's Database Queue Implementation](https://discuss.flarum.org/d/28151-database-queue-the-simplest-queue-even-for-shared-hosting) as a basic queue solution. It contains instructions on how to enable the queue through a cron job. + +:::danger Cron Job PHP Process Version + +It is common for shared hosts to have a low php version used in SSH, users must be pointed to the fact that they have to make sure the php process is of a version compatible with Flarum. Either by manually checking or by asking their hosts. + +::: + +![Package Manager Queue Table Preview](/en/img/package-manager-queue.png) + +## TODO +- Try on shared hosting. +- Composer command job must not overlap. +- Code TODOs. +- Better explanation on the UI about background tasks. +- Take into consideration a scenario where we're updating an extension that isn't a root required dependency, like bundles. +- Run one background task at a time, prevent user from triggering multiple tasks. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/languages.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/languages.md new file mode 100644 index 000000000..a2e73079b --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/languages.md @@ -0,0 +1,29 @@ +# 多语言支持 + +为您的 Flarum 添加新的界面语言很简单。 按照下面的说明,下载并安装语言包即可。 + +在您安装并启用一个语言包后,您可以将其 [设置为您论坛的默认语言](#设置默认语言)。 当您可以 [随时禁用](#禁用语言包) 用不到的语言。 如果您有使用任何第三方扩展,请务必在开始前 [阅读社区扩展说明](#社区扩展)。 + +## 安装语言包 + +欲开始,请访问 Flarum 社区上的 [Extensions > Languages](https://discuss.flarum.org/t/languages) 标签,并找到您想要安装的语言包。 + +语言包的安装方式与 [扩展](extensions.md) 相同。 语言包安装成功后会出现在后台管理界面的 **Extensions(插件)** 页面中,您可以在该页面启用语言包。 + +完成! 您现在应该可以点击论坛顶部导航栏的语言选择器,将界面切换到新语言。 + +## 设置默认语言 + +如果安装的语言包能正常工作,您可能会想要将该语言设置为新用户和访客的默认语言。 您可以在后台管理面板的 **Basics(常规)** 页面中进行设置。 + +## 禁用语言包 + +当您不需要某种语言时,您可以选择关闭该语言。 只需在后台管理面板的 **Extensions(插件)** 页面中找到该语言包,然后将其关闭该语言包。 + +如果您的网站是单语网站,并且不希望语言选择器出现在论坛顶部的导航栏中,您可以禁用其他语言包。 当只有一种语言包处于启用状态时,语言选择器会自动隐藏。 + +## 社区扩展 + +虽然从 Flarum 社区中下载的语言包通常是包含所有 Flarum 原生捆绑扩展的翻译的,但是 _并没有规定说_ 语言包必须翻译了所有您安装的社区扩展。 是否提供、更新维护这些扩展的翻译取决于开发者的个人意愿。 + +因此,在您安装一个社区扩展前,请检查您使用的语言包是否包含了该扩展的翻译。 如果您发现了一个不支持您所需要语言的社区扩展,请直接联系开发者,让他/她添加翻译。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/mail.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/mail.md new file mode 100644 index 000000000..8e9142def --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/mail.md @@ -0,0 +1,29 @@ +# 电子邮件配置 + +社区需要发送邮箱验证、密码重置、消息,以及其他与用户交流的邮件。 作为论坛管理员,您首先要做的几件事之一就是配置好论坛的邮件服务! 配置错误的话,用户在注册时会收到报错。 + +## 支持的邮件驱动 + +Flarum 默认提供以下所列驱动。 若有需要,开发者可自行开发插件添加 [自定义邮件驱动](extend/mail.md)。 + +### SMTP + +这是最常用的邮件驱动,需要您配置主机地址、端口、加密方式、用户名和密码,以使用外部 SMTP 服务。 请注意,加密方式必须为小写的 `ssl` 或 `tls`。 + +### Mail + +`mail` 会用到许多托管服务器上都有的 sendmail / postfix 邮件系统。 您必须在服务器上正确安装并配置好 sendmail 才能正常工作。 + +### Mailgun + +通过您的 [Mailgun](https://www.mailgun.com/) 来发送邮件。 您需要填写 secret key,以及您在 Mailgun 配置的域名、区域。 + +要使用 Mailgun 驱动,您需要安装 Guzzle composer 包 (一个 PHP HTTP 客户端)。 在您的 Flarum 根目录下运行 `composer require guzzlehttp/guzzle:^6.0|^7.0` 。 + +### Log + +邮件驱动 log 不会发送邮件,主要由开发者使用。 它会在在`FLARUM_ROOT_DIRECTORY/storage/logs`中的日志文件写入所有邮件的内容。 + +## 测试邮件 + +在您保存邮件配置后,您可以在后台管理面板的邮件配置页面点击「发送测试邮件」发送一封邮件以检测您的配置是否可用。 如果提示错误,或者您没有收到测试邮件,那就意味着配置有误,请检查配置然后重试。 如果没有任何报错,邮件也发送出去了,但是您在收件箱中找不到测试邮件,请去垃圾箱看看,它很可能在那边。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/permissions.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/permissions.md new file mode 100644 index 000000000..d6bdbde2d --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/permissions.md @@ -0,0 +1,3 @@ +# 权限 +此页面正在建设中。 +This page is under construction. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/releases.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/releases.md new file mode 100644 index 000000000..7ad40e57f --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/releases.md @@ -0,0 +1,15 @@ +# 发布说明 + + + + +发布说明可以在 [Flarum 社区](https://discuss.flarum.org/t/blog?sort=newest) 找到。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/rest-api.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/rest-api.md new file mode 100644 index 000000000..93e96582c --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/rest-api.md @@ -0,0 +1,375 @@ +# 使用 REST API + +Flarum 提供了 REST API,它不仅被我们的单页应用使用着,也可供外部程序调用。 + +我们的 API 采用 [JSON:API](https://jsonapi.org/) 规范定义的最佳实践。 + +:::info + +若要扩展 REST API 以实现新的应用,请查看开发者文档《[API 与数据流](extend/api.md)》。 + +::: + +## 身份验证 + +我们的单页应用使用会话 Cookies 进行 API 的身份验证。 外部程序可使用 [API 密钥](#api-keys) 或 [访问令牌](#access-tokens) 的无状态身份验证。 + +`GET` 端点无需身份验证即可使用, 但此时只会返回游客可见的内容。 为防止 [CSRF 攻击](#csrf-protection),其他端点均需身份验证方可使用。 + +### API 密钥 + +脚本、工具与集成应用和 Flarum 的交互应当采用 API 秘钥作为首选方案。 + +#### 创建 + +目前没有用于管理 API 密钥的操作界面,您只能在数据库 `api_keys` 表中手动创建。 + +以下参数可在创建时提供: + +- `key`:秘钥。您需要自行生成一个独一无二的长字符串(推荐长度 40 的字母数字组合),秘钥将作为 `Authorization` 请求头的值。 +- `user_id`:用户 ID,可选项。 如果设置了此值,秘钥会被充当为指定的用户。 + +以下属性会被自动填充,部分作为保留字段尚未使用: + +- `id`:主键。由 MySQL 自动递增填写。 +- `allowed_ips`:IP 白名单。保留字段,尚未使用。 +- `scopes`:范围。保留字段,尚未使用。 +- `created_at`:创建时间。虽然可设置任意日期值,但理应表示秘钥的创建日期。 +- `last_activity_at`:上次使用时间。秘钥被使用时自动更新。 + +#### 使用 + +发起 API 请求时,将秘钥添加到 `Authorization` 请求头即可。 如需指定扮演用户角色,可在请求头末尾添加。 + + Authorization: Token 你的_API_秘钥_值; userId=1 + +如果在数据库中为密钥设置了 `user_id` 值,请求头中的 `userId=` 将被忽略。 否则,任何有效的用户 ID 都可起作用。 + +### 访问令牌 + +访问令牌(Access Tokens)是基于用户的短效令牌。 + +这些令牌用于 Cookie 会话, 使用他们与常规会话别无二致。 用户的上次在线时间会随访问令牌的使用而更新。 + +#### 创建 + +所有用户均可创建访问令牌。 要创建令牌,请使用 `/api/token` 端点并提供用户凭证: + +``` +POST /api/token HTTP/1.1 + +{ + "identification": "张三", + "password": "张三的密码" +} + +HTTP/1.1 200 OK + +{ + "token": "YACub2KLfe8mfmHPcUKtt6t2SMJOGPXnZbqhc3nX", + "userId": "1" +} +``` + +我们目前存在 3 种令牌类型,其中 2 种可以通过 REST API 创建。 + +- `session` 令牌在 1 小时没有活动后即会过期。 这是默认的令牌类型。 +- `session_remember` 令牌在 5 年没有活动后即会过期。 在请求体中添加 `remember=1` 属性即可获取这种令牌。 +- `developer` 令牌永不过期。 目前只可通过数据库手动创建这种令牌。 + +**所有令牌将在用户注销时一并失效**(包括 `developer` 令牌,不过我们计划改变这种状况)。 + +#### 使用 + +发起 API 请求时,将上一步取得的 `token` 添加到 `Authorization` 请求头即可: + + Authorization: Token YACub2KLfe8mfmHPcUKtt6t2SMJOGPXnZbqhc3nX + +### CSRF 保护 + +多数 `POST`/`PUT`/`DELETE` API 端点都有 [跨站请求伪造](https://en.wikipedia.org/wiki/Cross-site_request_forgery)(Cross-site request forgery,缩写 CSRF)保护功能。 因此,要发出无状态请求,必须进行身份验证。 + +使用 API 密钥或访问令牌时,可跳过 CSRF 保护。 + +## 端点 + +这部分文档仍在编写中。 我们正在研究如何为端点实现自动化文档。 + +每个扩展程序都可自行添加新的端点和属性,因此提供涵盖所有端点的文档。 若要查看端点,您可以使用浏览器的开发者工具检查单页应用发起的请求。 + +下面是一些常用接口的示例。 为方便阅读,部分 JSON 字段已略去。 + +### 列出全部主题帖 + + GET /api/discussions + +```json +{ + "links": { + "first": "https://flarum.tld/api/discussions", + "next": "https://flarum.tld/api/discussions?page%5Boffset%5D=20" + }, + "data": [ + { + "type": "discussions", + "id": "227", + "attributes": { + "title": "出师表", + "slug": "227-chu-shi-biao", + "commentCount": 10, + "participantCount": 3, + "createdAt": "0227-01-01T00:10:30+08:00", + "lastPostedAt": "0227-01-05T00:10:30+08:00", + "lastPostNumber": 10, + "canReply": true, + "canRename": true, + "canDelete": true, + "canHide": true, + "isHidden": true, + "hiddenAt": "0227-01-01T00:10:30+08:00", + "lastReadAt": "0227-01-01T00:10:30+08:00", + "lastReadPostNumber": 2, + "isApproved": true, + "canTag": true, + "isLocked": false, + "canLock": true, + "isSticky": false, + "canSticky": true, + "canMerge": true, + "subscription": null + }, + "relationships": { + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + "lastPostedUser": { + "data": { + "type": "users", + "id": "64" + } + }, + "tags": { + "data": [ + { + "type": "tags", + "id": "3" + } + ] + }, + "firstPost": { + "data": { + "type": "posts", + "id": "668" + } + } + } + }, + { + "type": "discussions", + "id": "234", + "attributes": { + // [...] + }, + "relationships": { + // [...] + } + }, + // [...] 更多主题 + ], + "included": [ + { + "type": "users", + "id": "1", + "attributes": { + "username": "Zhugeliang", + "displayName": "诸葛亮", + "avatarUrl": null, + "slug": "1" + } + }, + { + "type": "users", + "id": "64", + "attributes": { + "username": "Flarum", + "displayName": "Flarum", + "avatarUrl": "https://flarum.tld/assets/avatars/Z4hEncw0ndVqZ8be.png", + "slug": "64" + } + }, + { + "type": "tags", + "id": "3", + "attributes": { + "name": "欢迎", + "description": "在这里发送一些有趣的玩意儿", + "slug": "welcome", + "color": "#888", + "backgroundUrl": null, + "backgroundMode": null, + "icon": "fas fa-bullhorn", + "discussionCount": 30, + "position": 1, + "defaultSort": null, + "isChild": false, + "isHidden": false, + "lastPostedAt": "2022-01-05T10:20:30+00:00", + "canStartDiscussion": true, + "canAddToDiscussion": true, + "isRestricted": false + } + }, + { + "type": "posts", + "id": "668", + "attributes": { + "number": 1, + "createdAt": "2022-01-01T10:20:30+00:00", + "contentType": "comment", + "contentHtml": "

你好,世界!

" + } + }, + // [...] 其他包含内容 + ] +} +``` + +### 发布主题 + + POST /api/discussions + +```json +{ + "data":{ + "type": "discussions", + "attributes": { + "title": "这里是标题", + "content": "你好,世界!" + }, + "relationships": { + "tags": { + "data": [ + { + "type": "tags", + "id": "1" + } + ] + } + } + } +} +``` + +服务器响应含有新主题的 ID: + +```json +{ + "data": { + "type": "discussions", + "id": "42", + "attributes": { + "title": "这里是标题", + "slug": "42-gu-ding-lian-jie", + "commentCount": 1 + // [...] 其他属性 + }, + "relationships": { + "posts": { + "data": [ + { + "type": "posts", + "id": "58" + } + ] + }, + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + // [...] 其他关联内容 + } + }, + "included":[ + { + "type": "posts", + "id": "38", + "attributes": { + "number": 1, + "contentType": "comment", + "contentHtml": "\u003Cp\u003E你好,世界!\u003C\/p\u003E" + // [...] 其他属性 + } + } + // [...] 其他包含内容 + ] +} +``` + +### 注册用户 + + POST /api/users + +```json +{ + "data": { + "attributes": { + "username": "YongHuMing", + "email": "flarum@example.com", + "password": "MiMa" + } + } +} +``` + +## 错误 + +Flarum 使用不同的 HTTP 状态码进行错误应答,所有错误表述均符合 [JSON:API 错误规范](https://jsonapi.org/format/#errors)。 + +下面是您使用 REST API 时可能遇到的一些常见错误: + +### CSRF 令牌不匹配 + +如果您收到了消息为 `csrf_token_mismatch` 的 400 HTTP 错误,这意味着 `Authorization` 请求头缺失或无效,导致 Flarum 尝试通过会话 Cookie 进行身份验证。 + +```json +{ + "errors": [ + { + "status": "400", + "code": "csrf_token_mismatch" + } + ] +} +``` + +### 验证错误 + +验证错误会返回一个 HTTP 状态码 422 的响应。 无效字段的名称会以 `pointer` 值返回。 在同一时间,单个字段可能出现多个错误。 + +```json +{ + "errors": [ + { + "status": "422", + "code": "validation_error", + "detail": "The username has already been taken.", // 用户名已被使用 + "source":{ + "pointer":"\/data\/attributes\/username" + } + }, + { + "status": "422", + "code": "validation_error", + "detail": "The email has already been taken.", // 邮箱地址已被使用 + "source": { + "pointer":"\/data\/attributes\/email" + } + } + ] +} +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/scheduler.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/scheduler.md new file mode 100644 index 000000000..1a0b24913 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/scheduler.md @@ -0,0 +1,55 @@ +# 调度器 + +Flarum的调度器让扩展程序能够轻松地自动化某些任务。 在本指南中,我们将介绍如何设置它。 我们不会深入讨论cron本身的细节,但如果你想进一步了解它,我建议你查看[Wikipedia上关于cron的文章](https://en.wikipedia.org/wiki/Cron)。 + +## 为什么我要关心? + +很简单,现在有越来越多的扩展程序支持在后台自动为你处理某些功能。 想知道为什么`fof/drafts`的“定时发布”没有发布,抑或是`fof/best-answer`的“在X天后提醒用户设置最佳答案”功能没有被触发吗? 那是因为它们会自动用调度器服务来配置自己,但这一切配置的前提是一行简短的cron任务。 + +## 有什么扩展程序现在在使用调度器? + +最火的一些例子如下: + +- [FoF Best Answer](https://github.com/FriendsOfFlarum/best-answer) +- [FoF Drafts](https://github.com/FriendsOfFlarum/drafts) +- [FoF Sitemap](https://github.com/FriendsOfFlarum/sitemap) +- [FoF Open Collective](https://github.com/FriendsOfFlarum/open-collective) +- [FoF Github Sponsors](https://github.com/FriendsOfFlarum/github-sponsors) + +## 让我们配置起来! + +几乎所有(全部)Linux发行版本都自带或可以安装cron。 例如,在基于Debian和Ubuntu的系统上,你可以这样安装`cron`: + +``` +sudo apt-get update +sudo apt-get install cron +``` + +如果你使用的是基于RHEL的Linux发行版(如CentOS、AlmaLinux、Rocky Linux等),可以这样安装cron: + +``` +sudo dnf update +sudo dnf install crontabs +``` + +安装好了cron,让我们创建Flarum所需的唯一定时条目: + +``` +crontab -e +``` + +这将打开 cron 编辑器。 你或许会有其他 cron 条目,但没关系。 添加以下这行,并记住在底部留一个空行。 + +``` +* * * * * cd /path-to-your-project && php flarum schedule:run >> /dev/null 2>&1 +``` + +`* * * * *` 会告诉 cron 每分钟都来运行你的命令。 + +如果你想修改触发时间,但不确切知道 cron 表达式是如何工作的,你可以使用[cron表达式生成器](https://crontab.guru)来轻松获取所需的命令。 + +`cd /path-to-your-project && php flarum schedule:run` 这行代码将执行Flarum的调度器以触发当前所有等待运行的任务。 如果PHP不在你的系统路径中,你可能需要尝试设置PHP的完整路径。 + +最后,`>> /dev/null 2>&1` 抑制了命令的所有输出。 + +瞧! 现在任何注册了定时任务的扩展程序,从每分钟到每天、每月、每年,都将自动在你的服务器上运行。 diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/tags.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/tags.md new file mode 100644 index 000000000..cba515c89 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/tags.md @@ -0,0 +1,3 @@ +# 分类目录和标签 +此页面正在建设中。 +This page is under construction. diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/themes.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/themes.md new file mode 100644 index 000000000..318e55c86 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/themes.md @@ -0,0 +1,29 @@ +# 样式主题 + +尽管我们一直在努力使 Flarum 变得尽可能美丽,但每个社区可能都希望进行一些调整/修改,以适合他们所需的风格。 + +## 管理面板 + +[管理面板](admin.md) 的「外观」页面是自定义论坛的绝佳起点。 在这里,您可以: + +- 选择主题颜色 +- 切换夜间模式和彩色导航栏。 +- 上传标志和站点图标(浏览器标签中显示的图标)。 +- 在自定义页眉和页脚添加 HTML。 +- 添加 [自定义LESS/CSS](#css-主题) 来改变元素的显示方式。 + +## CSS 主题 + +CSS 是一种样式表语言,它告诉浏览器如何显示网页的元素。 它允许我们修改所有的东西,从颜色到字体到元素的大小,从定位到动画等等。 添加自定义 CSS 是修改您的 Flarum 默认主题的好方法。 + +CSS 教程不在本文档的讨论范围之内,但是有大量的优质在线资源可供您学习 CSS 的基础知识。 + +:::tip + +Flarum 其实使用了 LESS,它支持变量、条件和函数,可以让您更轻松地编写 CSS。 + +::: + +## 扩展 + +Flarum 灵活的 [扩展系统](extensions.md) 允许您添加、删除或修改 Flarum 的任何部分。 如果您想做实质性的主题修改,除了改变颜色/大小/样式之外,一个自定义的扩展绝对是您的最佳选择。 要学习如何制作扩展,请查看我们的 [扩展文档](extension/README.md)! diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md new file mode 100644 index 000000000..c660d9f53 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/troubleshoot.md @@ -0,0 +1,56 @@ +# 故障排查 + +如果 Flarum 没有按照预期那样安装或工作,您 *首先应该检查* 服务器环境是否符合 [系统要求](install.md#环境要求)。 如果您缺少一些 Flarum 运行所需的东西,请先补全内容。 + +然后,请花几分钟时间搜索 [支持论坛](https://discuss.flarum.org/t/support)和 [问题跟踪器](https://github.com/flarum/core/issues),有可能该问题已被报告,并且有了解决办法。 有可能已经有人报告了该问题,而且修复方案已经可用或正在开发中。 如果您彻底搜索后,仍然没有找到任何有用的信息,那么就可以开始排查故障了。 + +## 步骤 0:开启调试模式 + +:::danger 在生产环境下跳过 + +这些调试工具非常有用,但可能会暴露不应公开的信息。 如果你在暂存或开发环境中,这些是可以的。但是如果你不知道你在做什么,那么请在生产环境中跳过这个步骤。 + +::: + +在继续前,您应当启用 Flarum 的调试模式。 用文本编辑器打开 **config.php**,将 `debug` 的值改为 `true`,然后保存文件即可。 开启后,Flarum 会显示详细的错误报告,方便您了解到底发生了什么。 + +如果上面的改动不起任何作用,并且论坛所有页面都变成空白,请试试将 **php.ini** 文件中的 `display_errors` 设置为 `On`。 + +## 步骤 1:常见问题修复 + +很多问题都可通过以下解决: + +* 清除浏览器缓存。 +* 使用 [`php flarum cache:clear`](console.md) 清除后端缓存。 +* 确保以使用 [`php flarum migrate`](console.md) 更新数据库。 +* 确保 [邮箱配置](mail.md) 可用:无效的邮箱配置将导致注册、重置密码、更换用户绑定邮箱以及发送通知时产生错误。 +* 检查 `config.php` 配置是否正确,请确保您使用了正确的 `url`。 例如,请确保正在使用正确的 `URL`(`https` 与 `http` 或大小写敏感之类的,这很重要!) +* 罪魁祸首还可能是自定义页眉、自定义页脚或自定义 LESS。 如果你的问题在前端,请尝试通过删除管理员仪表板中外观页面的设置。 + +您也得看看 [`php flarum info`](console.md) 的输出,以确保没有什么大的问题。 + +## 步骤 2:问题重现 + +请尝试让问题重现。 注意问题发生时,您在做什么? 是每次都会出现问题,还是仅偶尔出现? 尝试调整您觉得可能影响问题出现的设置或参数,或者改变您的操作顺序看看。 问题是否在某些情况下会出现,而在某些情况下又不会出现? + +如果您最近安装或更新了一个扩展程序,请暂时禁用它,然后看看问题有没有消失。 请确保您启用的所有扩展程序兼容您使用的 Flarum 版本。 过时的扩展会导致各种各样的问题。 + +在这个过程中,您可能会发现导致问题的原因,并找到了解决办法。 即便没有,您也可能会得到一些有价值的线索,您最好在报告中填写好这些信息,这将帮助我们弄清楚出了什么问题。 + +## 步骤 3:收集信息 + +如果您无法解决问题,需要他人的帮助,那么就是时候认真收集数据了。 请从这些地方搜集相关报错内容或其他与问题有关的信息: + +* 论坛页面上显示的报错 +* 浏览器控制台中显示的报错(Chrome:更多工具 -> 开发者工具 -> Console) +* 服务器错误日志中记录的内容(例如:`/var/log/nginx/error.log`) +* PHP-FPM 错误日志中记录的内容(例如:`/var/log/php7.x-fpm.log`) +* Flarum 日志记录的报错(`storage/logs/flarum.log`) + +将收集到的所有信息复制到记事本中,整理好并做一些注解,比如错误是 *何时* 发生的、当错误发生时您在 *做什么*、您探索出来的问题发生和不发生的条件。 请务必附加上你已经知道的关于问题复现条件的信息。 请尽可能详尽地提供服务器环境信息,如操作系统版本、Web 服务器版本、PHP 版本和处理程序等。 + +## 步骤 4:准备报告 + +竭尽所能收集相关问题的所有信息后,您就可以提交错误报告了。 提交时请遵循 [提交 Bug](bugs.md) 的有关说明。 + +如果您在提交报告后有发现新的情况,请添加到您的原始帖子底部。 倘若您已经自行解决了问题,也最好提交一份报告,说不定能帮助到遇到同样问题的其他用户。 如果您找到了临时的解决办法,也请告诉我们。 \ No newline at end of file diff --git a/i18n/zh/docusaurus-plugin-content-docs/version-1.x/update.md b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/update.md new file mode 100644 index 000000000..713ac769f --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/version-1.x/update.md @@ -0,0 +1,110 @@ +# 更新 + +## From the Admin Dashboard + +:::info + +If you have the extension manager extension installed you can simply run the update from its interface and skip this page entirely. + +::: + +--- + +您需要使用 [Composer](https://getcomposer.org) 来更新 Flarum。 如果你不熟悉它(尽管你应该是熟悉的,因为你需要它来安装Flarum),阅读 [我们的指南](composer.md) 了解它是什么以及如何设置它。 + +如果跨主要版本进行更新(如 <=0.1.0 to 1.x.x, 1.x.x 到 2.x.x.x, ... ),请确保在运行一般升级步骤之前阅读相应的“主要版本更新指南”。 + +## 一般步骤 + +**第1步:**确保你所有的扩展程序的版本与你要安装的Flarum版本兼容。 这只在主要版本之间需要(例如,如果从v1.0.0升级到v1.1.0,你可能不需要检查这个,假设你使用的扩展遵循建议的版本划分)。 你可以通过查看扩展的[讨论贴](https://discuss.flarum.org/t/extensions),在[Packagist](http://packagist.org/)上搜索它,或者查看[Extiverse](https://extiverse.com)等数据库来检查。 在更新之前,您需要删除(不仅仅禁用) 任何不兼容的扩展。 请耐心等待扩展开发者更新! + +**第2步:** 查看您的 `composer.json` 文件。 除非您有理由要求特定版本的扩展或库; 您应该将除 `flarum/core` 以外的所有版本字符串设置为 `*` (包括 `flarum/tags`, `flarum/mention`和其他捆绑的扩展)。 但请确认 `flarum/core` 未设置为 `*`。 如果你针对的是特定版本的Flarum, 请设置 `flarum/core` 为指定版本(例如, `"flarum/core": "v0.1.0-bet.16`)。 如果你只想要最新的版本,请使用 `"flarum/core": "^1.0"`。 + +**第 3步:** 如果您使用 [本地扩展](extenders.md),请确保它们更新到最新的 Flarum 中的变更。 + +**第 4 步:** 我们建议在更新之前在管理面板禁用第三方扩展。 这不是严格需要的,但如果您遇到问题,将更容易调试问题。 + +**第 5步:** 请确保您的 PHP 版本被您正在尝试升级到 Flarum 的版本所支持。 并且你正在使用Composer 2(`composer --version)` + +**步骤6:** 最后更新,运行: + +``` +composer update --prefer-dist --no-plugins --no-dev -a --with-all-dependencies +php flarum migrate +php flarum cache:clear +``` + +**步骤7:** 如果可以,请重启您的 PHP 进程和opcache。 + +## 主要版本更新指南 + +### 从 Beta (<= 0.1.0) 更新到 Stable v1 (^1.0.0) + +1. 执行上文步骤1-5。 +2. Change the version strings of all bundled extensions (`flarum/tags`, `flarum/mentions`, `flarum/likes`, etc) in `composer.json` from `^0.1.0` to `*`. +3. Change `flarum/core`'s version string in `composer.json` from `^0.1.0` to `^1.0`. +4. Remove the `"minimum-stability": "beta",` line from your `composer.json` +5. Do steps 6 and 7 above. + +## 故障排除 + +Flarum 正处于测试阶段,有关如何更新的说明将在每次 [版本发布公告](https://discuss.flarum.org/t/blog?sort=newest)中公示。 + +### 更新时出错 + +这里我们将会处理尝试更新 Flarum 时出现的几种常见问题。 + +--- + +如果输出较短且包含: + +``` +Nothing to modify in lock file +``` + +Or does not list `flarum/core` as an updated package, and you are not on the latest flarum version: + +- Revisit step 2 above, make sure that all third party extensions have an asterisk for their version string. +- Make sure your `flarum/core` version requirement isn't locked to a specific minor version (e.g. `v0.1.0-beta.16` is locked, `^1.0.0` isn't). If you're trying to update across major versions of Flarum, follow the related major version update guide above. + +--- + +For other errors, try running `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO` + +如果输出看起来像这样: + +``` +flarum/flarum - requires flarum/core (v0.1.0-beta.15) +fof/moderator-notes 0.4.4 requires flarum/core (>=0.1.0-beta.15 <0.1.0-beta.16) +jordanjay29/flarum-ext-summaries 0.3.2 requires flarum/core (>=0.1.0-beta.14 <0.1.0-beta.16) +flarum/core v0.1.0-beta.16 requires dflydev/fig-cookies (^3.0.0) +flarum/flarum - does not require dflydev/fig-cookies (but v2.0.3 is installed) +flarum/core v0.1.0-beta.16 requires franzl/whoops-middleware (^2.0.0) +flarum/flarum - does not require franzl/whoops-middleware (but 0.4.1 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/bus (^8.0) +flarum/flarum - does not require illuminate/bus (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/cache (^8.0) +flarum/flarum - does not require illuminate/cache (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/config (^8.0) +flarum/flarum - does not require illuminate/config (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/container (^8.0) +flarum/flarum - does not require illuminate/container (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/contracts (^8.0) +flarum/flarum - does not require illuminate/contracts (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/database (^8.0) +flarum/flarum - does not require illuminate/database (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/events (^8.0) +flarum/flarum - does not require illuminate/events (but v6.20.19 is installed) +... (this'll go on for a bit) +``` + +It is very likely that some of your extensions have not yet been updated. + +- Revisit step 1 again, make sure all your extensions have versions compatible with the core version you want to upgrade to. Remove any that don't. +- Make sure you're running `composer update` with all the flags specified in the update step. + +If none of this fixes your issue, feel free to reach out on our [Support forum](https://discuss.flarum.org/t/support). Make sure to include the output of `php flarum info` and `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO`. + +### Errors After Updating + +如果您在更新后无法访问您的论坛,请遵循我们的 [故障排除说明](troubleshoot.md)。 diff --git a/versioned_docs/version-1.x/README.md b/versioned_docs/version-1.x/README.md new file mode 100644 index 000000000..45d90f93e --- /dev/null +++ b/versioned_docs/version-1.x/README.md @@ -0,0 +1,45 @@ +--- +slug: / +--- + +# About Flarum + +Flarum is a delightfully simple discussion platform for your website. It's fast, free, and easy to use, with all the features you need to run a successful community. It's also extremely extensible, allowing for ultimate customizability. + +![Flarum Home Screenshot](/en/img/home_screenshot.png) + +## Goals + +Flarum is the combined successor of [esoTalk](https://github.com/esotalk/esoTalk) and [FluxBB](https://fluxbb.org). It is designed to be: + +* **Fast and simple.** No clutter, no bloat, no complex dependencies. Flarum is built with PHP so it’s quick and easy to deploy. The interface is powered by [Mithril](https://mithril.js.org), a performant JavaScript framework with a tiny footprint. + +* **Beautiful and responsive.** This is forum software for humans. Flarum is carefully designed to be consistent and intuitive across platforms, out-of-the-box. + +* **Powerful and extensible.** Customize, extend, and integrate Flarum to suit your community. Flarum’s architecture is amazingly flexible, with a [powerful Extension API](/extend/README.md). + +* **Free and open.** Flarum is released under the [MIT license](https://github.com/flarum/flarum/blob/master/LICENSE). + +You can read more about our [philosophy and values for Flarum here](https://discuss.flarum.org/d/28869-flarum-philosophy-and-values). + +## Help the Flarum Project + +Flarum is [free, open source](https://github.com/flarum/core) software, maintained and governed by volunteers. We rely on community contributions to help us improve and expand Flarum. + +🧑‍💻 If you're a developer, consider [contributing to Flarum's core or bundled extensions](contributing.md). This is **the** most efficient way to help Flarum, and your work can have a lot of impact: there are thousands of Flarum sites out there, with millions of total end users. + +🧩 If there's a feature you're missing, or a theme idea you have, [writing a custom extension](extend/README.md) will make Flarum that much better for you and others. + +✒️ If you're experienced in technical writing, your contributions to [our documentation](https://github.com/flarum/docs/issues) could help future users, admins, and developers make the most of Flarum. + +🌐 If you speak multiple languages, you could [contribute translations](extend/language-packs.md) to could help make Flarum accessible to countless users around the world. + +💸 The Flarum Foundation doesn't make money off of Flarum, but does have bills to pay. Donations via [GitHub Sponsors](https://github.com/sponsors/flarum) or [OpenCollective](https://opencollective.com/flarum) are always gratefully received. In the past, we've also been able to support some of our core developers financially, so they could work on Flarum part time. This wouldn't be possible without your financial support. + +🧑‍🤝‍🧑 Join [our community](https://discuss.flarum.org) to talk about Flarum development, get help with your instance, or just meet cool people! If you're experienced with Flarum, you can also help out beginners! + +🐛 If there's a bug that's bothering you, or a feature idea on your mind, we can't know about it unless you tell us! We track bugs, suggestions, and future development plans [via GitHub issues](https://github.com/flarum/core/issues). If there's already an issue open, adding likes and (constructive) additional information can be very helpful! + +📣 And if you like Flarum, please consider blogging/tweeting/talking about it! More people aware of Flarum leads to more people engaging with Flarum, and therefore more activity, better extensions, and faster development. + +Flarum wouldn't be possible without our phenomenal community. If you're interested in contributing, see our [developer contribution](contributing.md) and [other contribution](contributing-docs-translations.md) docs for more information. diff --git a/versioned_docs/version-1.x/admin.md b/versioned_docs/version-1.x/admin.md new file mode 100644 index 000000000..c412a14b7 --- /dev/null +++ b/versioned_docs/version-1.x/admin.md @@ -0,0 +1,15 @@ +# Admin Dashboard + +The Flarum Admin Dashboard is a user-friendly interface for managing your forum. +It is only available to users in the "Admin" group. +To access the Admin dashboard, Click on your **Name** at the at the top right of the screen, and select **Administration**. + +The Admin Dashboard has the following sections, being: +- **Dashboard** - Shows the main Admin Dashboard, containing statistics and other relevant information. +- **Basics** - Shows the options to set basic forum details such as Name, Description, and Welcome Banner. +- **Email** - Allows you to configure your E-Mail settings. Refer [here](https://docs.flarum.org/mail) for more information. +- **Permissions** - Shows the permissions for each user group, and allows you to configure global and specific scopes. +- **Appearance** - Allows you to customize the forum's colors, branding and add additional CSS for customization. +- **Users** - Provides you with a paginated list of all the users in the forum, and grants you the ability to edit the user or take administrative actions. + +Apart from the above mentioned sections, the Admin Dashboard also allows you to manage your Extensions (including the flarum core extensions such as Tags) under the _Features_ section. Extensions which modify the forum theme, or allow you to use multiple languages are categorized under the _Themes_ and _Languages_ section respectively. diff --git a/versioned_docs/version-1.x/bugs.md b/versioned_docs/version-1.x/bugs.md new file mode 100644 index 000000000..85e8ea193 --- /dev/null +++ b/versioned_docs/version-1.x/bugs.md @@ -0,0 +1,28 @@ +# Reporting Bugs + +:::danger Security Vulnerabilities + +If you discover a security vulnerability within Flarum, please follow our [security policy](https://github.com/flarum/core/security/policy) so we can address it promptly. + +::: + +Thank you for helping us test Flarum. We're happy to have you on the team! We need people who can *troubleshoot issues patiently* and *communicate them clearly*. As you probably know, good bug reporting takes some time and effort. If you're fine with that, then let's get started! + +## Duplicates + +Found a bug already? Wonderful! We'd love to hear about it — but first you should check around to make sure you're not wasting your time on a known issue: + +- Search our [Support forum](https://discuss.flarum.org/t/support) to see if it's already been reported. +- We could be working on a fix, so search our [issue tracker](https://github.com/flarum/core/issues) too. + +If you've searched *thoroughly* and come up empty-handed, we'll welcome your report. If it's just a simple issue (a misspelled word or graphics glitch, for example) skip to the next paragraph. But if you're seeing errors, or something is clearly broken, we'll need you to gather some information first. Please head over to our [Troubleshooting](troubleshoot.md) guide and follow the instructions there. Collect as much info as you can! + +## Reporting + +We track issues on GitHub. Make sure you open your issue in the [correct repository](https://github.com/flarum), and fill out all of the information in the Bug Report template. + +If you can, check if the issue is reproducible with the latest version of Flarum. If you are using a pre-release or development version, please indicate the specific version you are using. + +Remember: the goal of a bug report is to make it easy for us to replicate the bug and fix it. You might want to read [this article](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html) for some useful tips on how to write an effective bug report. It is **required** that you clearly describe the steps necessary to reproduce the issue you are running into. Issues with no clear reproduction steps will not be triaged. If an issue labeled "needs verification" receives no further input from the issue author for more than 5 days, it will be closed. + +Once you've posted your report, we'd ask that you please *follow the discussion* and wait patiently. We may need to ask for further details or clarification; but we've always got plenty to do, and it could be a while before we can give your report the time it deserves. diff --git a/versioned_docs/version-1.x/code-of-conduct.md b/versioned_docs/version-1.x/code-of-conduct.md new file mode 100644 index 000000000..1faf10eea --- /dev/null +++ b/versioned_docs/version-1.x/code-of-conduct.md @@ -0,0 +1,51 @@ +# Code of Conduct + +### _Welcome to the Flarum Community!_ + +... And thanks for joining us! We're excited about Flarum, and are always happy to meet people who feel the same way. We want *everyone* to get the most out of Flarum and the Flarum community, so we ask that you please read and follow these guidelines. These apply whether you're using our forum, Discord chat, communicating on GitHub, or any other form of communication without the Flarum community. + +### Above All, Be Cool! + +We're all here to talk about Flarum, and to work together toward making it an even better application. Criticizing ideas (by means of reasoned arguments, of course) is an important part of that. But let's not get carried away and devolve into personal attacks, because negativity only gets in the way. We ask that you avoid the following: + +- Offensive or abusive language, as well as any kind of hate speech +- Posts intended to harass, impersonate, or defame others +- Unnecessary deletion of posted content +- Attempts to abuse or expose the private information of others +- Obscene or sexually explicit content +- Spam, phishing posts, and any actions intended to deface this site +- Discussion of software piracy and similar topics + +*All the above are grounds for moderator action.* If you have an issue with another member, we ask that you please don't confront them yourself. If it's on the forum, please use the *Report* command on the post in question, then leave it up to the staff to deal with the situation. Otherwise, report the violation using our [contact page](https://flarum.org/foundation/contact), option Legal. + +Our moderators may edit or delete any content that is offensive or disruptive to the flow of communication. Serious or repeated offenses may lead to suspension of the offending user's account. So, you know, *be cool*. 😎 + +### Make Yourself Heard + +Want to start a new discussion? First, be sure to read [our FAQ](faq.md) and follow the links to make sure you're fully informed about the project. Then spend some time browsing the forum, familiarize yourself with [the tag system](https://discuss.flarum.org/tags), and do a few searches for keywords related to your topic: *it could be someone has already started a discussion about it!* + +When you're sure you're ready to start a discussion, please keep the following points in mind: + +- Give it a good title! You'll get the best results if your title makes it clear what you want to talk about. +- Choose the right tag(s). This will increase the likelihood your post will be read and answered promptly. +- *Don’t* post repeatedly about the same topic, as doing so will tend to have the opposite effect. +- If not using a tag set aside for multilingual use, *post in English only.* We can't help you if we don't understand your posts. +- Remember, you don't need to sign your posts. We've got your profile to let us know who you are. + +Please make the effort to help us keep things organized. Time spent tidying up is time that we can't spend getting to know you, discussing your issues, and talking about Flarum. And that, after all, is what we're all here to do! + +### Make Your Reply Count + +You're taking the time to participate in a discussion, in the hope that others will read your ideas and take them into consideration. So why not make the effort to make your reply worth reading? + +- Don't reply to a title. Take some time to *read* the OP, and at least *scan* the rest of the conversation first. +- Ask yourself if your reply adds to the discussion. If it doesn't, give it some more thought before posting. +- Avoid making one-word posts just to agree with someone; you can use the "Like" button for that. +- Avoid making multiple posts in a row when one would suffice. This is a forum, not a chat room. +- If your reply is likely to divert the course of the discussion, consider starting a new discussion instead. +- If you just want to post a bit of nonsense as a test, please do it in the [Test Posting](https://discuss.flarum.org/t/sandbox) tag instead. +- Make sure your replies provide constructive feedback and support to allow for an inclusive community. + +No one's going to complain about the occasional joke or smart remark. We like to keep the mood light! But to keep things productive, as well, we ask that you try to avoid derailing a discussion altogether. + +> Thanks to Dominion for his help in putting these guidelines together. diff --git a/versioned_docs/version-1.x/composer.md b/versioned_docs/version-1.x/composer.md new file mode 100644 index 000000000..627f81821 --- /dev/null +++ b/versioned_docs/version-1.x/composer.md @@ -0,0 +1,155 @@ + +# Composer + +Flarum uses a program called [Composer](https://getcomposer.org) to manage its dependencies and extensions. +You'll need to use composer if you want to: + +- Install or update Flarum through the command line +- Install, update, or remove Flarum extensions through the command line + +This guide is provided as a brief explanation of Composer. We highly recommend consulting the [official documentation](https://getcomposer.org/doc/00-intro.md) for more information. + +:::tip Shared Hosting + +On shared hosting it is recommended to use the Extension Manager extension instead of Composer. It is a graphical interface for Composer that allows you to install, update and remove extensions without the need for SSH access. +You can directly install Flarum using an archive file, without the need for Composer. With the extension manager pre-installed, check the [installation guide](install.md#installing-by-unpacking-an-archive) for more information. + +::: + +## What is Composer? + +> Composer is a tool for dependency management in PHP. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you. — [Composer Introduction](https://getcomposer.org/doc/00-intro.md](https://getcomposer.org/doc/00-intro.md)) + +Each Flarum installation consists primarily of Flarum core and a set of [extensions](extensions.md). Each of these has its own dependencies and releases. + +Back in the day, forum frameworks would manage extensions by having users upload zip files with the extension code. That seems simple enough, but issues quickly become evident: + +- Uploading random zip files from the internet tends to be a bad idea. Requiring that extensions be downloaded from a central source like [Packagist](https://packagist.org/) makes it somewhat more tedious to spam malicious code, and ensures that source code is available on GitHub for free/public extensions. +- Let's say Extension A requires v4 of some library, and Extension B requires v5 of that same library. With a zip-based solution, either one of the two dependencies could override the other, causing all sorts of inconsistent problems. Or both would attempt to run at once, which would cause PHP to crash (you can't declare the same class twice). +- Zip files can cause a lot of headache if trying to automate deployments, run automated tests, or scale to multiple server nodes. +- There is no good way to ensure conflicting extension versions can't be installed, or that system PHP version and extension requirements are met. +- Sure, we can upgrade extensions by replacing the zip file. But what about upgrading Flarum core? And how can we ensure that extensions can declare which versions of core they're compatible with? + +Composer takes care of all these issues, and more! + +## Flarum and Composer + +When you go to [install Flarum](install.md#installing), you're actually doing 2 things: + +1. Downloading a boilerplate "skeleton" for Flarum. This includes an `index.php` file that handles web requests, a `flarum` file that provides a CLI, and a bunch of web server config and folder setup. This is taken from the [`flarum/flarum` github repository](https://github.com/flarum/flarum), and doesn't actually contain any of the code necessary for Flarum to run. +2. Installing `composer` packages necessary for Flarum, namely Flarum core, and several bundled extensions. These are called by the `index.php` and `flarum` files from step 1, and are the implementation of Flarum. These are specified in a `composer.json` file included in the skeleton. + +When you want to update Flarum or add/update/remove extensions, you'll do so by running `composer` commands. Each command is different, but all commands follow the same general process: + +1. Update the `composer.json` file to add/remove/update the package. +2. Do a bunch of math to get the latest compatible versions of everything if possible, or figure out why the requested arrangement is impossible. +3. If everything works, download new versions of everything that needs to be updated. If not, revert the `composer.json` changes + +When running `composer.json` commands, make sure to pay attention to the output. If there's an error, it'll probably tell you if it's because of extension incompatibilities, an unsupported PHP version, missing PHP extensions, or something else. + +### The `composer.json` File + +As mentioned above, the entire composer configuration for your Flarum site is contained inside the `composer.json` file. You can consult the [composer documentation](https://getcomposer.org/doc/04-schema.md) for a specific schema, but for now, let's go over an annotated `composer.json` from `flarum/flarum`: + +```json +{ + // This following section is mostly just metadata about the package. + // For forum admins, this doesn't really matter. + "name": "flarum/flarum", + "description": "Delightfully simple forum software.", + "type": "project", + "keywords": [ + "forum", + "discussion" + ], + "homepage": "https://flarum.org/", + "license": "MIT", + "authors": [ + { + "name": "Flarum", + "email": "info@flarum.org", + "homepage": "https://flarum.org/team" + } + ], + "support": { + "issues": "https://github.com/flarum/core/issues", + "source": "https://github.com/flarum/flarum", + "docs": "https://flarum.org/docs/" + }, + // End of metadata + + // This next section is the one we care about the most. + // It's a list of packages we want, and the versions for each. + // We'll discuss this shortly. + "require": { + "flarum/core": "^1.0", + "flarum/approval": "*", + "flarum/bbcode": "*", + "flarum/emoji": "*", + "flarum/lang-english": "*", + "flarum/flags": "*", + "flarum/likes": "*", + "flarum/lock": "*", + "flarum/markdown": "*", + "flarum/mentions": "*", + "flarum/nicknames": "*", + "flarum/pusher": "*", + "flarum/statistics": "*", + "flarum/sticky": "*", + "flarum/subscriptions": "*", + "flarum/suspend": "*", + "flarum/tags": "*" + }, + + // Various composer config. The ones here are sensible defaults. + // See https://getcomposer.org/doc/06-config.md for a list of options. + "config": { + "preferred-install": "dist", + "sort-packages": true + }, + + // If composer can find a stable (not dev, alpha, or beta) version + // of a package, it should use that. Generally speaking, production + // sites shouldn't run beta software unless you know what you're doing. + "prefer-stable": true +} +``` + +Let's focus on that `require` section. Each entry is the name of a composer package, and a version string. +To read more about version strings, see the relevant [composer documentation](https://semver.org/). + +For Flarum projects, there's several types of entries you'll see in the `require` section of your root install's `flarum/core`: + +- You MUST have a `flarum/core` entry. This should have an explicit version string corresponding to the major release you want to install. For Flarum 1.x versions, this would be `^1.0`. +- You should have an entry for each extension you've installed. Some bundled extensions are included by default (e.g. `flarum/tags`, `flarum/suspend`, etc), [others you'll add via composer commands](extensions.md). Unless you have a reason to do otherwise (e.g. you're testing a beta version of a package), we recommend using an asterisk as the version string for extensions (`*`). This means "install the latest version compatible with my flarum/core". +- Some extensions / features might require PHP packages that aren't Flarum extensions. For example, you need the guzzle library to use the [Mailgun mail driver](mail.md). In these cases, the instructions for the extension/feature in question should explain which version string to use. + +## How to install Composer? + +As with any other software, Composer must first be [installed](https://getcomposer.org/download/) on the server where Flarum is running. There are several options depending on the type of web hosting you have. + +### Dedicated Web Server + +In this case you can install composer as recommended in the Composer [guide](https://getcomposer.org/doc/00-intro.md#system-requirements) + +### Managed / Shared hosting + +If Composer is not preinstalled (you can check this by running `composer --version`), you can use a [manual installation](https://getcomposer.org/composer-stable.phar). Just upload the composer.phar to your folder and run `/path/to/your/php7 composer.phar COMMAND` for any command documented as `composer COMMAND`. + +:::danger + +Some articles on the internet will mention that you can use tools like a PHP shell. If you are not sure what you are doing or what they are talking about - be careful! An unprotected web shell is **extremely** dangerous. + +::: + +## How do I use Composer? + +You'll need to use Composer over the **C**ommand-**l**ine **i**nterface (CLI). Be sure you can access your server over **S**ecure **Sh**ell (SSH). + +Once you have Composer installed, you should be able to run Composer commands in your SSH terminal via `composer COMMAND`. + +:::info Optimizations + +After most commands, you'll want to run `composer dump-autoload -a`. Essentially, this caches PHP files so they run faster. + +::: diff --git a/versioned_docs/version-1.x/config.md b/versioned_docs/version-1.x/config.md new file mode 100644 index 000000000..2b23101e9 --- /dev/null +++ b/versioned_docs/version-1.x/config.md @@ -0,0 +1,36 @@ +# Configuration File + +There is only one place where Flarum configuration cannot be modified through the Flarum admin dashboard (excluding the database), and that is the `config.php` file located in the root of your Flarum installation. + +This file, though small, contains details that are crucial for your Flarum installation to work. + +If the file exists, it tells Flarum that it has already been installed. +It also provides Flarum with database info and more. + +Here's a quick overview of what everything means with an example file: + +```php + false, // enables or disables debug mode, used to troubleshoot issues + 'offline' => false, // enables or disables site maintenance mode. This makes your site inaccessible to all users (including admins). + 'database' => + array ( + 'driver' => 'mysql', // the database driver, i.e. MySQL, MariaDB... + 'host' => 'localhost', // the host of the connection, localhost in most cases unless using an external service + 'database' => 'flarum', // the name of the database in the instance + 'username' => 'root', // database username + 'password' => '', // database password + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', // the prefix for the tables, useful if you are sharing the same database with another service + 'port' => '3306', // the port of the connection, defaults to 3306 with MySQL + 'strict' => false, + ), + 'url' => 'https://flarum.localhost', // the URL installation, you will want to change this if you change domains + 'paths' => + array ( + 'api' => 'api', // /api goes to the API + 'admin' => 'admin', // /admin goes to the admin + ), +); +``` diff --git a/versioned_docs/version-1.x/console.md b/versioned_docs/version-1.x/console.md new file mode 100644 index 000000000..92d4fcf45 --- /dev/null +++ b/versioned_docs/version-1.x/console.md @@ -0,0 +1,77 @@ +# Console + +In addition to the admin dashboard, Flarum provides several console commands to help manage your forum over the terminal. + +Using the console: + +1. `ssh` into the server where your flarum installation is hosted +2. `cd` to the folder that contains the file `flarum` +3. Run the command via `php flarum [command]` + +## Default Commands + +### list + +Lists all available management commands, as well as instructions for using management commands + +### help + +`php flarum help [command_name]` + +Displays help output for a given command. + +You can also output the help in other formats by using the --format option: + +`php flarum help --format=xml list` + +To display the list of available commands, please use the list command. + +### info + +`php flarum info` + +Get information about Flarum's core and installed extensions. This is very useful for debugging issues, and should be shared when requesting support. + +### cache:clear + +`php flarum cache:clear` + +Clears the backend flarum cache, including generated js/css, text formatter cache, and cached translations. This should be run after installing or removing extensions, and running this should be the first step when issues occur. + +### assets:publish + +`php flarum assets:publish` + +Publish assets from core and extensions (e.g. compiled JS/CSS, bootstrap icons, logos, etc). This is useful if your assets have become corrupted, or if you have switched [filesystem drivers](extend/filesystem.md) for the `flarum-assets` disk. + +### migrate + +`php flarum migrate` + +Runs all outstanding migrations. This should be used when an extension that modifies the database is added or updated. + +### migrate:reset + +`php flarum migrate:reset --extension [extension_id]` + +Reset all migrations for an extension. This is mostly used by extension developers, but on occasion, you might need to run this if you are removing an extension, and want to clear all of its data from the database. Please note that the extension in question must currently be installed (but not necessarily enabled) for this to work. + +### schedule:run + +`php flarum schedule:run` + +Many extensions use scheduled jobs to run tasks on a regular interval. This could include database cleanups, posting scheduled drafts, generating sitemaps, etc. If any of your extensions use scheduled jobs, you should add a [cron job](https://ostechnix.com/a-beginners-guide-to-cron-jobs/) to run this command on a regular interval: + +``` +* * * * * cd /path-to-your-flarum-install && php flarum schedule:run >> /dev/null 2>&1 +``` + +This command should generally not be run manually. + +Note that some hosts do not allow you to edit cron configuration directly. In this case, you should consult your host for more information on how to schedule cron jobs. + +### schedule:list + +`php flarum schedule:list` + +This command returns a list of scheduled commands (see `schedule:run` for more information). This is useful for confirming that commands provided by your extensions are registered properly. This **can not** check that cron jobs have been scheduled successfully, or are being run. \ No newline at end of file diff --git a/versioned_docs/version-1.x/contributing-docs-translations.md b/versioned_docs/version-1.x/contributing-docs-translations.md new file mode 100644 index 000000000..c30e96dda --- /dev/null +++ b/versioned_docs/version-1.x/contributing-docs-translations.md @@ -0,0 +1,26 @@ +# Docs and Translation + +## Add Documentation + +Adding documentation can help countless future Flarum users. A few ideas of what to work on: + +- User guides to help Flarum end users with some advanced Flarum features. +- More [frequently asked questions](faq.md). +- Expanded [troubleshooting](troubleshoot.md) steps. +- Step-by-step tutorials for Flarum development or installation. +- [Technical reference guides](extend/README.md) for extension developers. +- Improving literally anything else you think we should elaborate on or explain better. + +A good way to find topics to write about is to look for common questions in the [support tag](https://discuss.flarum.org/t/support) of our community. + +## Translate Flarum + +We want Flarum to be accessible to everyone, regardless of language! By contributing translations, you make it possible for many more people to enjoy Flarum. Best of all, we use user-friendly GUIs for translations, so no technical skills are necessary to help! + +Translations for Flarum core, bundled extensions, and community extensions are managed through [Weblate](https://weblate.rob006.net/projects/flarum/). + +Translations for this documentation are managed through [Crowdin](https://crowdin.com/project/flarum-docs). + +The Flarum Foundation has created the "flarum-lang" organization to support translators and ensure continuous availability of language packs. You can learn more about this by [visiting the GitHub repository](https://github.com/flarum-lang/about). + +If you want to support an existing language pack, start a new translation, or you run into issues using weblate or crowdin, it's best to [get in touch with the `flarum-lang` team](https://discuss.flarum.org/d/27519-the-flarum-language-project). diff --git a/versioned_docs/version-1.x/contributing.md b/versioned_docs/version-1.x/contributing.md new file mode 100644 index 000000000..4fc952fd9 --- /dev/null +++ b/versioned_docs/version-1.x/contributing.md @@ -0,0 +1,171 @@ +# Help Build Flarum + +Interested in contributing to Flarum development? That's great! From [opening a bug report](bugs.md) to creating a pull request: every single one is appreciated and welcome. Flarum wouldn't be possible without our community contributions. + +Before contributing, please read the [code of conduct](code-of-conduct.md). + +This document is a guide for developers who want to contribute code to Flarum. If you're just getting started, we recommend that you read the [Getting Started](/extend/start.md) documentation in the Extension docs to understand a bit more about how Flarum works. + +## Why Contribute to Flarum? + +⚡ **Have Real Impact.** There are thousands of Flarum instances, with millions of aggregate end users. By contributing to Flarum, your code will have a positive impact on all of them. + +🔮 **Shape the Future of Flarum.** We have a long backlog, and limited time. If you're willing to champion a feature or change, it's much more likely to happen, and you'll be able to enact your vision for it. Plus, our roadmap and milestones are set by our [core development team](https://flarum.org/team), and all of us started as contributors. The best road to influence is contributing. + +🧑‍💻 **Become a Better Engineer.** Our codebase is modern, and we heavily value good engineering and clean code. There's also a lot of interesting, challenging problems to solve regarding design, infrastructure, performance, and extensibility. Especially if you're a student or early in your career, working on Flarum is a great opportunity to build development skills. + +🎠 **It's Fun!** We really enjoy working on Flarum: there's a lot of interesting challenges and fun features to build. We also have an active community on [our forums](https://discuss.flarum.org) and [Discord server](https://flarum.org/chat). + +## What to Work On + +Check out our upcoming [Milestones](https://github.com/flarum/core/milestones) for an overview of what needs to be done. See the [Good first issue](https://github.com/flarum/core/labels/Good%20first%20issue) label for a list of issues that should be relatively easy to get started with. If there's anything you're unsure of, don't hesitate to ask! All of us were just starting out once. + +If you're planning to go ahead and work on something, please comment on the relevant issue or create a new one first. This way we can ensure that your precious work is not in vain. + +Since Flarum is so extension-driven, we highly recommend [our extension docs](extend/README.md) as a reference when working on core, as well as for bundled extensions. You should start with [the introduction](extend/README.md) for a better understanding of our extension philosophy. + +## Development Setup + +### Setting Up a Local Codebase + +[flarum/flarum](https://github.com/flarum/flarum) is a "skeleton" application which uses Composer to download the core package and a bunch of extensions. Source code for Flarum core, extensions, and all packages used by the aforementioned is located in the Flarum monorepo [flarum/framework](https://github.com/flarum/framework). In order to contribute to these, you'll need to fork and clone the monorepo repository locally, and then add it to your dev environment as a [Composer path repository](https://getcomposer.org/doc/05-repositories.md#path): + +```bash +git clone https://github.com/flarum/flarum.git +cd flarum + +# Or, when you want to clone directly into the current directory +git clone https://github.com/flarum/flarum.git . +# Note, the directory must be empty + +# Set up a Composer path repository for Flarum monorepo packages +composer config repositories.0 path "PATH_TO_MONOREPO/*/*" +git clone https://github.com//framework.git PATH_TO_MONOREPO +``` + +Next, ensure that Composer accepts unstable releases from your local copies by setting the `minimum-stability` key to `dev` in `composer.json`. + +Finally, run `composer install` to complete the installation from the path repositories. + +After your local installation is set up, make sure you've enabled `debug` mode in **config.php**, and set `display_errors` to `On` in your php config. This will allow you to see error details for both Flarum and PHP. Debug mode also forces a re-compilation of Flarum's asset files on each request, removing the need to call `php flarum cache:clear` after each change to the extension's JavaScript or CSS. + +Flarum's front-end code is written in ES6 and transpiled into JavaScript. During development you will need to recompile the JavaScript using [Node.js](https://nodejs.org/) and [`yarn`](https://yarnpkg.com/). **Please do not commit the resulting `dist` files when sending PRs**; this is automatically taken care of when changes are merged into the `main` branch. + +To contribute to the frontend, first install the JavaScript dependencies. The monorepo uses [yarn workspaces](https://classic.yarnpkg.com/lang/en/docs/workspaces/) to easily install JS dependencies across all packages within. + +```bash +cd packages/framework +yarn install +``` + +Then you can watch JavaScript files for changes during development: + +```bash +cd framework/core/js +yarn dev +``` + +The process is the same for extensions. + +```bash +cd extensions/tags/js +yarn dev +``` + +### Development Tools + +After you've forked and cloned the repositories you'll be working on, you'll need to set up local hosting so you can test out your changes. +Flarum doesn't currently come with a development server, so you'll need to set up Apache/NGINX/Caddy/etc to serve this local Flarum installation. + +Alternatively, you can use tools like, [Laravel Valet](https://laravel.com/docs/master/valet) (Mac), [XAMPP](https://www.apachefriends.org/index.html) (Windows), or [Docker-Flarum](https://github.com/mondediefr/docker-flarum) (Linux) to serve a local forum. + +Most Flarum contributors develop with [PHPStorm](https://www.jetbrains.com/phpstorm/download/) or [Visual Studio Code](https://code.visualstudio.com/). + +## Development Workflow + +A typical contribution workflow looks like this: + +0. 🧭 **Plan** out your contribution + * Figure out [which issue you want to tackle](#what-to-work-on) + * Set up a [development environment](#setting-up-a-local-codebase) + +1. 🌳 **Branch** off the appropriate branch into a new feature branch. + * *Bug fixes* should be sent to the latest stable branch. + * *Minor* features that are fully backwards compatible with the current Flarum release may be sent to the latest stable branch. + * *Major* features should always be sent to the `main` branch, which contains the upcoming Flarum release. + * Internally we use the naming scheme `/` (eg. `tz/refactor-frontend`). + +2. 🔨 **Write** some code. + * See below about [Coding Style](#coding-style). + +3. 🚦 **Test** your code. + * Add unit tests as necessary when fixing bugs or adding features. + * Run the test suite with `vendor/bin/phpunit` in the relevant package folder. + * See [here](extend/testing.md) for more information about testing in Flarum. + +4. 💾 **Commit** your code with a descriptive message. + * If your change resolves an existing issue (usually, it should) include "Fixes #123" on a newline, where 123 is the issue number. + * Follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) specification. + * *Fix* commits should describe the issue fixed, not how it was fixed. + +5. 🎁 **Submit** a Pull Request on GitHub. + * Fill out the pull request template. + * If your change is visual, include a screenshot or GIF demonstrating the change. + * Do NOT check-in the JavaScript `dist` files. These will be compiled automatically on merge. + +6. 🤝 **Engage** with the Flarum team for approval. + * Team members will review your code. We may suggest some changes or improvements or alternatives, but for small changes your pull request should be accepted quickly. + * When addressing feedback, push additional commits instead of overwriting or squashing (we will squash on merge). + +7. 🕺 **Dance** like you just contributed to Flarum. + +## Coding Style + +In order to keep the Flarum codebase clean and consistent, we have a number of coding style guidelines that we follow. When in doubt, read the source code. + +Don't worry if your code styling isn't perfect! StyleCI and Prettier will automatically check formatting for every pull request. This allows us to focus on the content of the contribution, not the code style. + +### PHP + +Flarum follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) coding standard and the [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) autoloading standard. On top of this, we conform to a number of [other style rules](https://github.com/flarum/framework/blob/main/.styleci.yml). We use PHP 7 type hinting and return type declarations where possible, and [PHPDoc](https://docs.phpdoc.org/) to provide inline documentation. Try and mimic the style used by the rest of the codebase in your contributions. + +* Namespaces should be singular (eg. `Flarum\Discussion`, not `Flarum\Discussions`) +* Interfaces should be suffixed with `Interface` (eg. `MailableInterface`) +* Abstract classes should be prefixed with `Abstract` (eg. `AbstractModel`) +* Traits should be suffixed with `Trait` (eg. `ScopeVisibilityTrait`) + +### JavaScript + +Flarum's JavaScript mostly follows the [Airbnb Style Guide](https://github.com/airbnb/javascript). We use [ESDoc](https://esdoc.org/manual/tags.html) to provide inline documentation. + +### Database + +**Columns** should be named according to their data type: +* DATETIME or TIMESTAMP: `{verbed}_at` (eg. created_at, read_at) or `{verbed}_until` (eg. suspended_until) +* INT that is a count: `{noun}_count` (eg. comment_count, word_count) +* Foreign key: `{verbed}_{entity}_id` (eg. hidden_user_id) + * Verb can be omitted for primary relationship (eg. post author is just `user_id`) +* BOOL: `is_{adjective}` (eg. is_locked) + +**Tables** should be named as follows: +* Use plural form (`discussions`) +* Separate multiple words with underscores (`access_tokens`) +* For relationships tables, join the two table names in singular form with an underscore in alphabetical order (eg. `discussion_user`) + +### CSS + +Flarum's CSS classes roughly follow the [SUIT CSS naming conventions](https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md) using the format `.ComponentName-descendentName--modifierName`. + +### Translations + +We use a [standard key format](/extend/i18n.md#appendix-a-standard-key-format) to name translation keys descriptively and consistently. + +## Contributor License Agreement + +By contributing your code to Flarum you grant the Flarum Foundation (Stichting Flarum) a non-exclusive, irrevocable, worldwide, royalty-free, sublicensable, transferable license under all of Your relevant intellectual property rights (including copyright, patent, and any other rights), to use, copy, prepare derivative works of, distribute and publicly perform and display the Contributions on any licensing terms, including without limitation: (a) open source licenses like the MIT license; and (b) binary, proprietary, or commercial licenses. Except for the licenses granted herein, You reserve all right, title, and interest in and to the Contribution. + +You confirm that you are able to grant us these rights. You represent that You are legally entitled to grant the above license. If Your employer has rights to intellectual property that You create, You represent that You have received permission to make the Contributions on behalf of that employer, or that Your employer has waived such rights for the Contributions. + +You represent that the Contributions are Your original works of authorship, and to Your knowledge, no other person claims, or has the right to claim, any right in any invention or patent related to the Contributions. You also represent that You are not legally obligated, whether by entering into an agreement or otherwise, in any way that conflicts with the terms of this license. + +The Flarum Foundation acknowledges that, except as explicitly described in this Agreement, any Contribution which you provide is on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. \ No newline at end of file diff --git a/versioned_docs/version-1.x/extend/README.md b/versioned_docs/version-1.x/extend/README.md new file mode 100644 index 000000000..ed31d9f1a --- /dev/null +++ b/versioned_docs/version-1.x/extend/README.md @@ -0,0 +1,40 @@ +--- +slug: '/extend' +--- + +# Extending Flarum + +Flarum is minimalistic, but it's also highly extensible. In fact, most of the features that ship with Flarum are actually extensions! + +This approach makes Flarum extremely customizable. A user can disable any features they don't use on their forum, and install other extensions to make a forum perfect for their community. + +In order to achieve this extensibility, Flarum has been built with rich APIs and extension points. With some programming knowledge, you can leverage these APIs to add just about any feature you want. This section of the documentation aims to teach you how Flarum works, and how to use the APIs so that you can build your own extensions. + +## Core vs. Extensions + +Where do we draw the line between Flarum's core and its extensions? Why are some features included in the core, and others aren't? It is important to understand this distinction so that we can maintain consistency and quality within Flarum's ecosystem. + +**Flarum's core** is not intended to be packed full of features. Rather, it is a scaffold, or a framework, which provides a reliable foundation on which extensions can build. It contains only basic, unopinionated functionality that is essential to a forum: discussions, posts, users, groups, and notifications. + +**Bundled extensions** are features that are packaged with Flarum and enabled by default. They are extensions just like any other, and may be disabled and uninstalled. While their scope is not intended to address all use-cases, the idea is to make them generic and configurable enough that they can satisfy the majority. + +**Third-party extensions** are features which are made by others and are not officially supported by the Flarum team. They can be built and used to address more specific use-cases. + +If you are aiming to address a bug or shortcoming of the core, or of an existing bundled extension, it may be appropriate to *contribute to the respective project* rather than disperse effort on a new third-party extension. It is a good idea to start a discussion on the [Flarum Community](https://discuss.flarum.org/) to get the perspective of the Flarum developers. + +## Useful Resources + +- [This Documentation](start.md) +- [Tips for Beginning Developers](https://discuss.flarum.org/d/5512-extension-development-tips) +- [Flarum CLI](https://github.com/flarum/cli) +- [Developers explaining their workflow for extension development](https://discuss.flarum.org/d/6320-extension-developers-show-us-your-workflow) +- [Extension namespace tips](https://discuss.flarum.org/d/9625-flarum-extension-namespacing-tips) +- [Mithril js documentation](https://mithril.js.org/) +- [Laravel API Docs](https://laravel.com/api/8.x/) +- [Flarum API Docs](https://api.flarum.org) +- [ES6 cheatsheet](https://github.com/DrkSephy/es6-cheatsheet) + +### Getting help + +- [Official Flarum Dev Community](https://discuss.flarum.org/t/dev) +- [Join us on #extend in our discord chat](https://flarum.org/discord/) diff --git a/versioned_docs/version-1.x/extend/admin.md b/versioned_docs/version-1.x/extend/admin.md new file mode 100644 index 000000000..dd0bbfad1 --- /dev/null +++ b/versioned_docs/version-1.x/extend/admin.md @@ -0,0 +1,214 @@ +# Admin Dashboard + +Beta 15 introduced a completely redesigned admin panel and frontend API. It is now easier than ever to add settings or permissions to your extension. + +Before beta 15, extension settings were either added in a `SettingsModal` or they added a new page for more complex settings. Now, every extension has a page containing info, settings, and the extension's own permissions. + +You can simply register settings, extend the base [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage), or provide your own completely custom page. + +## Extension Data API + +This new API allows you to add settings to your extension with very few lines of code. + +### Telling the API about your extension + +Before you can register anything, you need to tell `ExtensionData` what extension it is about to get data for. + +Simply run the `for` function on `app.extensionData` passing in the id of your extension. To find you extension id, take the composer name and replace any slashes with dashes (example: 'fof/merge-discussions' becomes 'fof-merge-discussions'). Extensions with the `flarum-` and `flarum-ext-` will omit those from the name (example: 'webbinaro/flarum-calendar' becomes 'webbinaro-calendar'). + +For the following example, we will use the fictitious extension 'acme/interstellar': + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') +}); +``` + +Once that is done, you can begin adding settings and permissions. + +:::tip Note + +All registration functions on `ExtensionData` are chainable, meaning you can call them one after another without running `for` again. + +::: + +### Registering Settings + +Adding settings fields in this way is recommended for simple items. As a rule of thumb, if you only need to store things in the settings table, this should be enough for you. + +To add a field, call the `registerSetting` function after `for` on `app.extensionData` and pass a 'setting object' as the first argument. Behind the scenes `ExtensionData` actually turns your settings into an [`ItemList`](https://api.docs.flarum.org/js/master/class/src/common/utils/itemlist.ts~itemlist), you can pass a priority number as the second argument. + +Here's an example with a switch (boolean) item: + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerSetting( + { + setting: 'acme-interstellar.coordinates', // This is the key the settings will be saved under in the settings table in the database. + label: app.translator.trans('acme-interstellar.admin.coordinates_label'), // The label to be shown letting the admin know what the setting does. + help: app.translator.trans('acme-interstellar.admin.coordinates_help'), // Optional help text where a longer explanation of the setting can go. + type: 'boolean', // What type of setting this is, valid options are: boolean, text (or any other tag type), and select. + }, + 30 // Optional: Priority + ) +}); +``` + +If you use `type: 'select'` the setting object looks a little bit different: + +```js +{ + setting: 'acme-interstellar.fuel_type', + label: app.translator.trans('acme-interstellar.admin.fuel_type_label'), + type: 'select', + options: { + 'LOH': 'Liquid Fuel', // The key in this object is what the setting will be stored as in the database, the value is the label the admin will see (remember to use translations if they make sense in your context). + 'RDX': 'Solid Fuel', + }, + default: 'LOH', +} +``` + +Also, note that additional items in the setting object will be used as component attrs. This can be used for placeholders, min/max restrictions, etc: + +```js +{ + setting: 'acme-interstellar.crew_count', + label: app.translator.trans('acme-interstellar.admin.crew_count_label'), + type: 'number', + min: 1, + max: 10 +} +``` + +If you want to add something to the settings like some extra text or a more complicated input, you can also pass a callback as the first argument that returns JSX. This callback will be executed in the context of [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) and setting values will not be automatically serialized. + +```js + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerSetting(function () { + if (app.session.user.username() === 'RocketMan') { + + return ( +
+

{app.translator.trans('acme-interstellar.admin.you_are_rocket_man_label')}

+ +
+ ); + } + }) +}); +``` + +### Registering Permissions + +New in beta 15, permissions can now be found in 2 places. Now, you can view each extension's individual permissions on their page. All permissions can still be found on the permissions page. + +In order for that to happen, permissions must be registered with `ExtensionData`. This is done in a similar way to settings, call `registerPermission`. + +Arguments: + * Permission object + * What type of permission - see [`PermissionGrid`](https://api.docs.flarum.org/js/master/class/src/admin/components/permissiongrid.js~permissiongrid)'s functions for types (remove items from the name) + * `ItemList` priority + +Back to our favorite rocket extension: + +```js +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerPermission( + { + icon: 'fas fa-rocket', // Font-Awesome Icon + label: app.translator.trans('acme-interstellar.admin.permissions.fly_rockets_label'), // Permission Label + permission: 'discussion.rocket_fly', // Actual permission name stored in database (and used when checking permission). + tagScoped: true, // Whether it be possible to apply this permission on tags, not just globally. Explained in the next paragraph. + }, + 'start', // Category permission will be added to on the grid + 95 // Optional: Priority + ); +}); +``` + +If your extension interacts with the [tags extension](https://github.com/flarum/tags) (which is fairly common), you might want a permission to be tag scopable (i.e. applied on the tag level, not just globally). You can do this by including a `tagScoped` attribute, as seen above. Permissions starting with `discussion.` will automatically be tag scoped unless `tagScoped: false` is indicated. + +To learn more about Flarum permissions, see [the relevant docs](permissions.md). + +### Chaining Reminder + +Remember these functions can all be chained like: + +```js +app.extensionData + .for('acme-interstellar') + .registerSetting(...) + .registerSetting(...) + .registerPermission(...) + .registerPermission(...); +``` + +### Extending/Overriding the Default Page + +Sometimes you have more complicated settings that mess with relationships, or just want the page to look completely different. In this case, you will need to tell `ExtensionData` that you want to provide your own page. Note that `buildSettingComponent`, the util used to register settings by providing a descriptive object, is available as a method on `ExtensionPage` (extending from `AdminPage`, which is a generic base for all admin pages with some util methods). + +Create a new class that extends the `Page` or `ExtensionPage` component: + +```js +import ExtensionPage from 'flarum/admin/components/ExtensionPage'; + +export default class StarPage extends ExtensionPage { + content() { + return ( +

Hello from the settings section!

+ ) + } +} + +``` + +Then, simply run `registerPage`: + +```js + +import StarPage from './components/StarPage'; + +app.initializers.add('interstellar', function(app) { + + app.extensionData + .for('acme-interstellar') + .registerPage(StarPage); +}); +``` + +This page will be shown instead of the default. + +You can extend the [`ExtensionPage`](https://api.docs.flarum.org/js/master/class/src/admin/components/extensionpage.js~extensionpage) or extend the base `Page` and design your own! + +## Composer.json Metadata + +In beta 15, extension pages make room for extra info which is pulled from extensions' composer.json. + +For more information, see the [composer.json schema](https://getcomposer.org/doc/04-schema.md). + +| Description | Where in composer.json | +| --------------------------------- | -------------------------------------- | +| discuss.flarum.org discussion link | "forum" key inside "support" | +| Documentation | "docs" key inside "support" | +| Support (email) | "email" key inside "support" | +| Website | "homepage" key | +| Donate | "funding" key block (Note: Only the first link will be used) | +| Source | "source" key inside "support" | diff --git a/versioned_docs/version-1.x/extend/api-throttling.md b/versioned_docs/version-1.x/extend/api-throttling.md new file mode 100644 index 000000000..b53d955dd --- /dev/null +++ b/versioned_docs/version-1.x/extend/api-throttling.md @@ -0,0 +1,61 @@ +# API Throttling + +Flarum comes with a builtin `Flarum\Api\Middleware\ThrottleApi` [middleware](middleware.md) for throttling requests to the API. +This runs on every API route, and extensions can add their own custom logic to throttle requests. + +:::caution Forum Routes + +Some forum routes (login, register, forgot password, etc) work by calling an API route under the surface. +The `ThrottleApi` middleware does not currently run for these requests, but that is planned for the future. + +::: + +## Custom Throttlers + +The format for a custom throttler is extremely simple: all you need is a closure or invokable class that takes the current request as an argument, and returns one of: + +- `false`: This explicitly bypasses throttling for this request, overriding all other throttlers +- `true`: This marks the request as to be throttled. +- `null`: This means that this throttler doesn't apply. +Any other outputs will be ignored, with the same effect as `null`. + +Throttlers will be run on EVERY request, and are responsible for figuring out whether or not they apply. For example, consider Flarum's post throttler: + +```php +use DateTime; +use Flarum\Post\Post; + +function ($request) { + if (! in_array($request->getAttribute('routeName'), ['discussions.create', 'posts.create'])) { + return; + } + + $actor = $request->getAttribute('actor'); + + if ($actor->can('postWithoutThrottle')) { + return false; + } + + if (Post::where('user_id', $actor->id)->where('created_at', '>=', new DateTime('-10 seconds'))->exists()) { + return true; + } +}; +``` + +Throttlers can be added or removed via the `ThrottleApi` middleware in `extend.php`. For example: + +```php +set('throttleAll', function () { + return false; + }) + ->remove('bypassThrottlingAttribute'), + // Other extenders +]; +``` diff --git a/versioned_docs/version-1.x/extend/api.md b/versioned_docs/version-1.x/extend/api.md new file mode 100644 index 000000000..0f1ad5322 --- /dev/null +++ b/versioned_docs/version-1.x/extend/api.md @@ -0,0 +1,359 @@ +# API and Data Flow + +In the [previous article](models.md), we learned how Flarum uses models to interact with data. Here, we'll learn how to get that data from the database to the JSON-API to the frontend, and all the way back again. + +:::info + +To use the built-in REST API as part of an integration, see [Consuming the REST API](../rest-api.md). + +::: + +## API Request Lifecycle + +Before we go into detail about how to extend Flarum's data API, it's worth thinking about the lifecycle of a typical API request: + +![Flarum API Flowchart](/en/img/api_flowchart.png) + +1. An HTTP request is sent to Flarum's API. Typically, this will come from the Flarum frontend, but external programs can also interact with the API. Flarum's API mostly follows the [JSON:API](https://jsonapi.org/) specification, so accordingly, requests should follow [said specification](https://jsonapi.org/format/#fetching). +2. The request is run through [middleware](middleware.md), and routed to the proper controller. You can learn more about controllers as a whole on our [routes and content documentation](routes.md). Assuming the request is to the API (which is the case for this section), the controller that handles the request will be a subclass of `Flarum\Api\AbstractSerializeController`. +3. Any modifications done by extensions to the controller via the [`ApiController` extender](#extending-api-controllers) are applied. This could entail changing sort, adding includes, changing the serializer, etc. +4. The `$this->data()` method of the controller is called, yielding some raw data that should be returned to the client. Typically, this data will take the form of a Laravel Eloquent model collection or instance, which has been retrieved from the database. That being said, the data could be anything as long as the controller's serializer can process it. Each controller is responsible for implementing its own `data` method. Note that for `PATCH`, `POST`, and `DELETE` requests, `data` will perform the operation in question, and return the modified model instance. +5. That data is run through any pre-serialization callbacks that extensions register via the [`ApiController` extender](#extending-api-controllers). +6. The data is passed through a [serializer](#serializers), which converts it from the backend, database-friendly format to the JSON:API format expected by the frontend. It also attaches any related objects, which are run through their own serializers. As we'll explain below, extensions can [add / override relationships and attributes](#attributes-and-relationships) at the serialization level. +7. The serialized data is returned as a JSON response to the frontend. +8. If the request originated via the Flarum frontend's `Store`, the returned data (including any related objects) will be stored as [frontend models](#frontend-models) in the frontend store. + +## API Endpoints + +We learned how to use models to interact with data, but we still need to get that data from the backend to the frontend. +We do this by writing API Controller [routes](routes.md), which implement logic for API endpoints. + +As per the JSON:API convention, we'll want to add separate endpoints for each operation we support. Common operations are: + +- Listing instances of a model (possibly including searching/filtering) +- Getting a single model instance +- Creating a model instance +- Updating a model instance +- Deleting a single model instance + +We'll go over each type of controller shortly, but once they're written, you can add these five standard endpoints (or a subset of them) using the `Routes` extender: + +```php + (new Extend\Routes('api')) + ->get('/tags', 'tags.index', ListTagsController::class) + ->get('/tags/{id}', 'tags.show', ShowTagController::class) + ->post('/tags', 'tags.create', CreateTagController::class) + ->patch('/tags/{id}', 'tags.update', UpdateTagController::class) + ->delete('/tags/{id}', 'tags.delete', DeleteTagController::class) +``` + +:::caution + +Paths to API endpoints are not arbitrary! To support interactions with frontend models: + +- The path should either be `/prefix/{id}` for get/update/delete, or `/prefix` for list/create. +- the prefix (`tags` in the example above) must correspond to the JSON:API model type. You'll also use this model type in your serializer's `$type` attribute, and when registering the frontend model (`app.store.models.TYPE = MODEL_CLASS`). +- The methods must match the example above. + +Also, remember that route names (`tags.index`, `tags.show`, etc) must be unique! + +::: + +The `Flarum\Api\Controller` namespace contains a number of abstract controller classes that you can extend to easily implement your JSON-API resources. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically create your endpoint controllers: +```bash +$ flarum-cli make backend api-controller +``` + +::: + +### Listing Resources + +For the controller that lists your resource, extend the `Flarum\Api\Controller\AbstractListController` class. At a minimum, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a collection of models. The `data` method accepts the `Request` object and the tobscure/json-api `Document`. + +```php +use Flarum\Api\Controller\AbstractListController; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ListTagsController extends AbstractListController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + return Tag::all(); + } +} +``` + +#### Pagination + +You can allow the number of resources being **listed** to be customized by specifying the `limit` and `maxLimit` properties on your controller: + +```php + // The number of records included by default. + public $limit = 20; + + // The maximum number of records that can be requested. + public $maxLimit = 50; +``` + +You can then extract pagination information from the request using the `extractLimit` and `extractOffset` methods: + +```php +$limit = $this->extractLimit($request); +$offset = $this->extractOffset($request); + +return Tag::skip($offset)->take($limit); +``` + +To add pagination links to the JSON:API document, use the `Document::addPaginationLinks` method. + +#### Sorting + +You can allow the sort order of resources being **listed** to be customized by specifying the `sort` and `sortField` properties on your controller: + +```php + // The default sort field and order to use. + public $sort = ['name' => 'asc']; + + // The fields that are available to be sorted by. + public $sortFields = ['firstName', 'lastName']; +``` + +You can then extract sorting information from the request using the `extractSort` method. This will return an array of sort criteria which you can apply to your query: + +```php +use Illuminate\Support\Str; + +// ... + +$sort = $this->extractSort($request); +$query = Tag::query(); + +foreach ($sort as $field => $order) { + $query->orderBy(Str::snake($field), $order); +} + +return $query->get(); +``` + +#### Searching and Filtering + +Read our [searching and filtering](search.md) guide for more information! + +### Showing a Resource + +For the controller that shows a single resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the list controller, you need to specify the `$serializer` you want to use to serialize your models, and implement a `data` method to return a single model. We'll learn about serializers [in just a bit](#serializers). + +```php +use Flarum\Api\Controller\AbstractShowController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class ShowTagController extends AbstractShowController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + return Tag::findOrFail($id); + } +} +``` + +### Creating a Resource + +For the controller that creates a resource, extend the `Flarum\Api\Controller\AbstractCreateController` class. This is the same as the show controller, except the response status code will automatically be set to `201 Created`. You can access the incoming JSON:API document body via `$request->getParsedBody()`: + +```php +use Flarum\Api\Controller\AbstractCreateController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; +use Tobscure\JsonApi\Document; + +class CreateTagController extends AbstractCreateController +{ + public $serializer = TagSerializer::class; + + protected function data(Request $request, Document $document) + { + $attributes = Arr::get($request->getParsedBody(), 'data.attributes'); + + return Tag::create([ + 'name' => Arr::get($attributes, 'name') + ]); + } +} +``` + +### Updating a Resource + +For the controller that updates a resource, extend the `Flarum\Api\Controller\AbstractShowController` class. Like for the create controller, you can access the incoming JSON:API document body via `$request->getParsedBody()`. + +### Deleting a Resource + +For the controller that deletes a resource, extend the `Flarum\Api\Controller\AbstractDeleteController` class. You only need to implement a `delete` method which enacts the deletion. The controller will automatically return an empty `204 No Content` response. + +```php +use Flarum\Api\Controller\AbstractDeleteController; +use Illuminate\Support\Arr; +use Psr\Http\Message\ServerRequestInterface as Request; + +class DeleteTagController extends AbstractDeleteController +{ + protected function delete(Request $request) + { + $id = Arr::get($request->getQueryParams(), 'id'); + + Tag::findOrFail($id)->delete(); + } +} +``` + +### Including Relationships + +To include relationships when **listing**, **showing**, or **creating** your resource, specify them in the `$include` and `$optionalInclude` properties on your controller: + +```php + // The relationships that are included by default. + public $include = ['user']; + + // Other relationships that are available to be included. + public $optionalInclude = ['discussions']; +``` + +You can then get a list of included relationships using the `extractInclude` method. This can be used to eager-load the relationships on your models before they are serialized: + +```php +$relations = $this->extractInclude($request); + +return Tag::all()->load($relations); +``` + +### Extending API Controllers + +It is possible to customize all of these options on _existing_ API controllers too via the `ApiController` extender + +```php +use Flarum\Api\Event\WillGetData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->setSerializer(MyDiscussionSerializer::class) + ->addInclude('user') + ->addOptionalInclude('posts') + ->setLimit(20) + ->setMaxLimit(50) + ->setSort(['name' => 'asc']) + ->addSortField('firstName') + ->prepareDataQuery(function ($controller) { + // Add custom logic here to modify the controller + // before data queries are executed. + }) +] +``` + +The `ApiController` extender can also be used to adjust data before serialization + +```php +use Flarum\Api\Event\WillSerializeData; +use Flarum\Api\Controller\ListDiscussionsController; +use Illuminate\Contracts\Events\Dispatcher; + +return [ + (new Extend\ApiController(ListDiscussionsController::class)) + ->prepareDataForSerialization(function ($controller, $data, $request, $document) { + $data->load('myCustomRelation'); + }), +] +``` + +## Serializers + +Before we can send our data to the frontend, we need to convert it to JSON:API format so that it can be consumed by the frontend. +You should become familiar with the [JSON:API specification](https://jsonapi.org/format/). +Flarum's JSON:API layer is powered by the [tobscure/json-api](https://github.com/tobscure/json-api) library. + +A serializer is just a class that converts some data (usually [Eloquent models](models.md#backend-models)) into JSON:API. +Serializers serve as intermediaries between backend and frontend models: see the [model documentation](models.md) for more information. +To define a new resource type, create a new serializer class extending `Flarum\Api\Serializer\AbstractSerializer`. You must specify a resource `$type` and implement the `getDefaultAttributes` method which accepts the model instance as its only argument: + +```php +use Flarum\Api\Serializer\AbstractSerializer; +use Flarum\Api\Serializer\UserSerializer; + +class DiscussionSerializer extends AbstractSerializer +{ + protected $type = 'discussions'; + + protected function getDefaultAttributes($discussion) + { + return [ + 'title' => $discussion->title, + ]; + } +} +``` + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically create your serializer: +```bash +$ flarum-cli make backend api-serializer +``` + +::: + +### Attributes and Relationships + +You can also specify relationships for your resource. Simply create a new method with the same name as the relation on your model, and return a call to `hasOne` or `hasMany` depending on the nature of the relationship. You must pass in the model instance and the name of the serializer to use for the related resources. + +```php + protected function user($discussion) + { + return $this->hasOne($discussion, UserSerializer::class); + } +``` + +### Extending Serializers + +To add **attributes** and **relationships** to an existing resource type, use the `ApiSerializer` extender: + +```php +use Flarum\Api\Serializer\UserSerializer; + +return [ + (new Extend\ApiSerializer(UserSerializer::class)) + // One attribute at a time + ->attribute('firstName', function ($serializer, $user, $attributes) { + return $user->first_name + }) + // Multiple modifications at once, more complex logic + ->mutate(function($serializer, $user, $attributes) { + $attributes['someAttribute'] = $user->someAttribute; + if ($serializer->getActor()->can('administrate')) { + $attributes['someDate'] = $serializer->formatDate($user->some_date); + } + + return $attributes; + }) + // API relationships + ->hasOne('phone', PhoneSerializer::class) + ->hasMany('comments', CommentSerializer::class), +] +``` + +### Non-Model Serializers and `ForumSerializer` + +Serializers don't have to correspond to Eloquent models: you can define JSON:API resources for anything. +For instance, Flarum core uses the [`Flarum\Api\Serializer\ForumSerializer`](https://api.docs.flarum.org/php/master/flarum/api/serializer/forumserializer) to send an initial payload to the frontend. This can include settings, whether the current user can perform certain actions, and other data. Many extensions add data to the payload by extending the attributes of `ForumSerializer`. diff --git a/versioned_docs/version-1.x/extend/assets.md b/versioned_docs/version-1.x/extend/assets.md new file mode 100644 index 000000000..e5fef4d1a --- /dev/null +++ b/versioned_docs/version-1.x/extend/assets.md @@ -0,0 +1,8 @@ +# Extension Assets + +Some extensions might want to include assets like images or JSON files in their source code (note that this is not the same as uploads, which would probably require a [filesystem disk](filesystem.md)). + +This is actually very easy to do. Just create an `assets` folder at the root of your extension, and place any asset files there. +Flarum will then automatically copy those files to its own `assets` directory (or other storage location if [one is offered by extensions](filesystem.md)) every time the extension is enabled or [`php flarum assets:publish`](../console.md) is executed. + +If using the default storage driver, assets will be available at `https://FORUM_URL/assets/extensions/EXTENSION_ID/file.path`. However, since other extensions might use remote filesystems, we recommend serializing the url to assets you need in the backend. See [Flarum's serialization of the logo and favicon URLs](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Serializer/ForumSerializer.php#L85-L86) for an example. diff --git a/versioned_docs/version-1.x/extend/authorization.md b/versioned_docs/version-1.x/extend/authorization.md new file mode 100644 index 000000000..b09fbe92b --- /dev/null +++ b/versioned_docs/version-1.x/extend/authorization.md @@ -0,0 +1,215 @@ +# Authorization + +As with any framework, Flarum allows certain actions and content to be restricted to certain users. There are 2 parallel systems for this: + +- The authorization process dictates whether a user can take a certain action. +- Visibility scoping can be applied to a database query to efficiently restrict the records that users can access. This is documented in our [model visibility](model-visibility.md) article. + +## Authorization Process + +The authorization process is used to check whether a person is allowed to perform certain actions. For instance, we want to check if a user is authorized before they: + +- Access the admin dashboard +- Start a discussion +- Edit a post +- Update another user's profile + +Each of these is determined by unique criteria: in some cases a flag is sufficient; otherwise, we might need custom logic. + +## How It Works + +Authorization queries are made with 3 parameters, with logic contained in [`Flarum\User\Gate`](https://api.docs.flarum.org/php/master/flarum/user/access/gate): + +1. The actor: the user attempting to perform the action +2. The ability: a string representing the action the actor is attempting +3. The arguments: usually an instance of a database model which is the subject of the attempted ability, but could be anything. + +First, we run the entire request (all three parameters) through all [policies](#policies) registered by extensions and core. Policies are blocks of logic provided by core and extensions that determine whether the actor can perform the ability on the arguments. Policies can return one of the following: + +- `Flarum\User\Access\AbstractPolicy::ALLOW` (via `$this->allow()`) +- `Flarum\User\Access\AbstractPolicy::DENY` (via `$this->deny()`) +- `Flarum\User\Access\AbstractPolicy::FORCE_ALLOW` (via `$this->forceAllow()`) +- `Flarum\User\Access\AbstractPolicy::FORCE_DENY` (via `$this->forceDeny()`) + +Policy results are considered in the priority `FORCE_DENY` > `FORCE_ALLOW` > `DENY` > `ALLOW`. For example, if a single policy returns `FORCE_DENY`, all other policies will be ignored. If one policy returns `DENY` and 10 policies return `ALLOW`, the request will be denied. This allows decisions to be made regardless of the order in which extensions are booted. Note that policies are extremely powerful: if access is denied at the policy stage, that will override group permissions and even admin privileges. + +Secondly, if all policies return null (or don't return anything), we check if the user is in a group that has a permission equal to the ability (note that both permissions and abilities are represented as strings). If so, we authorize the action. +See our [Groups and Permissions documentation](permissions.md) for more information on permissions. + +Then, if the user is in the admin group, we will authorize the action. + +Finally, as we have exhausted all checks, we will assume that the user is unauthorized and deny the request. + +## How To Use Authorization + +Flarum's authorization system is accessible through public methods of the `Flarum\User\User` class. The most important ones are listed below; others are documented in our [PHP API documentation](https://api.docs.flarum.org/php/master/flarum/user/user). + + +In this example, we will use `$actor` as an instance of `Flarum\User\User`, `'viewForum'` and `'reply'` as examples of abilities, and `$discussion` (instance of `Flarum\Discussion\Discussion`) as an example argument. + +```php +// Check whether a user can perform an action. +$canDoSomething = $actor->can('viewForum'); + +// Check whether a user can perform an action on a subject. +$canDoSomething = $actor->can('reply', $discussion); + +// Raise a PermissionDeniedException if a user cannot perform an action. +$actor->assertCan('viewForum'); +$actor->assertCan('reply', $discussion); + +// Raise a NotAuthenticatedException if the user is not logged in. +$actor->assertRegistered(); + +// Raise a PermissionDeniedException if the user is not an admin. +$actor->assertAdmin(); + +// Check whether one of the user's groups have a permission. +// WARNING: this should be used with caution, as it doesn't actually +// run through the authorization process, so it doesn't account for policies. +// It is, however, useful in implementing custom policies. +$actorHasPermission = $actor->hasPermission(`viewForum`); +``` + +## Custom Policies + +Policies allow us to use custom logic beyond simple groups and permissions when evaluating authorization for an ability with a subject. For instance: + +- We want to allow users to edit posts even if they aren't moderators, but only their own posts. +- Depending on settings, we might allow users to rename their own discussions indefinitely, for a short period of time after posting, or not at all. + +As described [above](#how-it-works), on any authorization check, we query all policies registered for the target's model, or any parent classes of the target's model. +If no target is provided, any policies registered as `global` will be applied. + +So, how does a policy get "checked"? + +First, we check if the policy class has a method with the same name as the ability being evaluated. +If so, we run it with the actor and subject as parameters. +If that method returns a non-null value, we return that result. Otherwise, we continue to the next step (not necessarily the next policy). + +Then, we check if the policy class has a method called `can`. If so, we run it with the actor, ability, and subject, and return the result. + +If `can` doesn't exist or returns null, we are done with this policy, and we proceed to the next one. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate policies: +```bash +$ flarum-cli make backend policy +``` + +::: + +### Example Policies + +Let's take a look at an example policy from [Flarum Tags](https://github.com/flarum/tags/blob/master/src/Access): + +```php +is_restricted) { + return $actor->hasPermission('tag'.$tag->id.'.startDiscussion') ? $this->allow() : $this->deny(); + } + } + + /** + * @param User $actor + * @param Tag $tag + * @return bool|null + */ + public function addToDiscussion(User $actor, Tag $tag) + { + return $this->startDiscussion($actor, $tag); + } +} +``` + +We can also have global policies, which are run when `$user->can()` is called without a target model instance. Again from Tags: + +```php +settings = $settings; + } + + /** + * @param Flarum\User\User $actor + * @param string $ability + * @return bool|void + */ + public function can(User $actor, string $ability) + { + if (in_array($ability, ['viewForum', 'startDiscussion'])) { + $enoughPrimary = count(Tag::getIdsWhereCan($actor, $ability, true, false)) >= $this->settings->get('min_primary_tags'); + $enoughSecondary = count(Tag::getIdsWhereCan($actor, $ability, false, true)) >= $this->settings->get('min_secondary_tags'); + + if ($enoughPrimary && $enoughSecondary) { + return $this->allow(); + } else { + return $this->deny(); + } + } + } +} +``` + +### Registering Policies + +Both model-based and global policies can be registered with the `Policy` extender in your `extend.php` file: + +```php +use Flarum\Extend; +use Flarum\Tags\Tag; +use YourNamespace\Access; + +return [ + // Other extenders + (new Extend\Policy()) + ->modelPolicy(Tag::class, Access\TagPolicy::class) + ->globalPolicy(Access\GlobalPolicy::class), + // Other extenders +]; +``` + +## Frontend Authorization + +Commonly, you'll want to use authorization results in frontend logic. +For example, if a user doesn't have permission to see search users, we shouldn't send requests to that endpoint. +And if a user doesn't have permission to edit users, we shouldn't show menu items for that. + +Because we can't do authorization checks in the frontend, we have to perform them in the backend, and attach them to serialization of data we're sending. +Global permissions (`viewForum`, `viewUserList`) can be included on the `ForumSerializer`, but for object-specific authorization, we may want to include those with the subject object. +For instance, when we return lists of discussions, we check whether the user can reply, rename, edit, and delete them, and store that data on the frontend discussion model. +It's then accessible via `discussion.canReply()` or `discussion.canEdit()`, but there's nothing magic there: it's just another attribute sent by the serializer. + +For an example of how to attach data to a serializer, see a [similar case for transmitting settings](settings.md#accessing-settings). diff --git a/versioned_docs/version-1.x/extend/backend-events.md b/versioned_docs/version-1.x/extend/backend-events.md new file mode 100644 index 000000000..2c63f4eef --- /dev/null +++ b/versioned_docs/version-1.x/extend/backend-events.md @@ -0,0 +1,174 @@ +# Backend Events + +Often, an extension will want to react to some events occuring elsewhere in Flarum. For instance, we might want to increment a counter when a new discussion is posted, send a welcome email when a user logs in for the first time, or add tags to a discussion before saving it to the database. These events are known as **domain events**, and are broadcasted across the framework through [Laravel's event system](https://laravel.com/docs/8.x/events). + +For a full list of backend events, see our [API documentation](https://api.docs.flarum.org/php/master/search.html?search=Event). Domain events classes are organized by namespace, usually `Flarum\TYPE\Event`. + + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate event listeners: +```bash +$ flarum-cli make backend event-listener +``` + +::: + +## Listening to Events + +You can attach a listener to an event using the [`Event`](https://api.docs.flarum.org/php/master/flarum/extend/event) [extender](start.md#extenders): + +```php +use Flarum\Extend; +use Flarum\Post\Event\Deleted; +use Symfony\Contracts\Translation\TranslatorInterface; + + +return [ + (new Extend\Event) + ->listen(Deleted::class, function($event) { + // do something here + }) + ->listen(Deleted::class, PostDeletedListener::class) +]; +``` +```php +class PostDeletedListener +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function handle(Deleted $event) + { + // Your logic here + } +} +``` + +As shown above, a listener class can be used instead of a callback. This allows you to [inject dependencies](https://laravel.com/docs/8.x/container) into your listener class via constructor parameters. In this example we resolve a translator instance, but we can inject anything we want/need. + +You can also listen to multiple events at once via an event subscriber. This is useful for grouping common functionality; for instance, if you want to update some metadata on changes to posts: + +```php +use Flarum\Extend; +use Flarum\Post\Event\Deleted; +use Flarum\Post\Event\Saving; +use Symfony\Contracts\Translation\TranslatorInterface; + + +return [ + (new Extend\Event) + ->subscribe(PostEventSubscriber::class), +]; +``` +```php +class PostEventSubscriber +{ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function subscribe($events) + { + $events->listen(Deleted::class, [$this, 'handleDeleted']); + $events->listen(Saving::class, [$this, 'handleSaving']); + } + + public function handleDeleted(Deleted $event) + { + // Your logic here + } + + public function handleSaving(Saving $event) + { + // Your logic here + } +} +``` + +## Dispatching Events + +Dispatching events is very simple. All you need to do is inject `Illuminate\Contracts\Events\Dispatcher` into your class, and then call its `dispatch` method. For instance: + +```php +use Flarum\Post\Event\Deleted; +use Illuminate\Contracts\Events\Dispatcher; + + +class SomeClass +{ + /** + * @var Dispatcher + */ + protected $events; + + /** + * @param Dispatcher $events + */ + public function __construct(Dispatcher $events) + { + $this->events = $events; + } + + public function someMethod() + { + // Logic + $this->events->dispatch( + new Deleted($somePost, $someActor) + ); + // More Logic + } +} +``` + +## Custom Events + +As an extension developer you can define your own events to allow yourself (or other extensions) to react to events in your extension. +Events are generally instances of simple classes (no need to extend anything). When defining a new event, you'll typically want to use public properties, and maybe some methods for convenience of users. +For example, if we take a look at `Flarum\Post\Event\Deleted`, it's just a wrapping around some data: + +```php +post = $post; + $this->actor = $actor; + } +} +``` diff --git a/versioned_docs/version-1.x/extend/cli.md b/versioned_docs/version-1.x/extend/cli.md new file mode 100644 index 000000000..2456ed478 --- /dev/null +++ b/versioned_docs/version-1.x/extend/cli.md @@ -0,0 +1,16 @@ +# Flarum CLI + +The Flarum development ecosystem is oriented around many small, modules, interacting extensions. +This is a very powerful and flexible paradigm, but it also brings the maintenance cost of creating and maintaining all these extensions. + +We've created the Flarum CLI (command line interface) as a tool to help developers by automating some repetitive and menial tasks, and allow them to get into the actual work without much hassle. + +Major updates about Flarum CLI will be published [on this discussion](https://discuss.flarum.org/d/28427-flarum-cli-v10). + +See the [package's readme](https://github.com/flarum/cli#readme) for information on: + +- Installation +- Usage +- Upgrading +- Available commands +- Some implementation details, if you're interested diff --git a/versioned_docs/version-1.x/extend/console.md b/versioned_docs/version-1.x/extend/console.md new file mode 100644 index 000000000..471d19681 --- /dev/null +++ b/versioned_docs/version-1.x/extend/console.md @@ -0,0 +1,70 @@ +# Console + +Flarum allows extension developers to add custom console commands in addition to the [default ones](../console.md) provided by flarum core. + +All console command development is done in the backend using PHP. To create a custom console command, you'll need to create a class that extends `\Flarum\Console\AbstractCommand`. + +```php +use Flarum\Console\AbstractCommand; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; + +class YourCommand extends AbstractCommand { + protected function configure() + { + $this + ->setName('YOUR COMMAND NAME') + ->setDescription('YOUR COMMAND DESCRIPTION'); + } + protected function fire() + { + // Your logic here! + } +} +``` + +:::info [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically generate and register a console command: +```bash +$ flarum-cli make backend command +``` + +::: + +## Registering Console Commands + +To register console commands, use the `Flarum\Extend\Console` extender in your extension's `extend.php` file: + +```php +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; + +return [ + // Other extenders + (new Extend\Console())->command(CustomCommand::class) + // Other extenders +]; +``` + +## Scheduled Commands + +The `Flarum\Extend\Console`'s `schedule` method allows extension developers to create scheduled commands that run on an interval: + + +```php +use Flarum\Extend; +use YourNamespace\Console\CustomCommand; +use Illuminate\Console\Scheduling\Event; + +return [ + // Other extenders + (new Extend\Console())->schedule('cache:clear', function (Event $event) { + $event->everyMinute(); + }, ['Arg1', '--option1', '--option2']), + // Other extenders +]; +``` + +In the callback provided as the second argument, you can call methods on the [$event object](https://laravel.com/api/8.x/Illuminate/Console/Scheduling/Event.html) to schedule on a variety of frequencies (or apply other options, such as only running on one server). See the [Laravel documentation](https://laravel.com/docs/8.x/scheduling#scheduling-artisan-commands) for more information. diff --git a/versioned_docs/version-1.x/extend/distribution.md b/versioned_docs/version-1.x/extend/distribution.md new file mode 100644 index 000000000..9f5f82566 --- /dev/null +++ b/versioned_docs/version-1.x/extend/distribution.md @@ -0,0 +1,41 @@ +# Distribution + +You've written a great extension — and now you want the whole world to be able to use it. This document will take you through the process of distribution, from setting up a Git repository for your extension, to publishing it on Packagist. + +## Setting Up Git + +The first thing you'll need to do is set up a version control system (VCS). +The most popular VCS is [Git](https://git-scm.com/). In this guide we'll be using Git, so make sure you have it [installed](https://git-scm.com/downloads) before continuing. If you don't have much Git knowledge, you may want to check out [these learning resources](https://try.github.io/). + +After you have installed Git, you'll need to initialize your repository. You can use `git init` on the command line if you're comfortable, or use a GUI tool like [SourceTree](https://www.sourcetreeapp.com/) or [GitKraken](https://www.gitkraken.com/). + +Then, you'll need an account in a Git hosting server, the most popular being [GitHub](https://github.com) and [GitLab](https://gitlab.com). These will instruct you on how to hook up your local repository with the online "remote" repository. + +## Tagging a Release + +As you are going to be publishing this extension, you'll want to make sure that the information is up to date. Take a minute to revisit `composer.json` and make sure package name, description, and Flarum extension information are all correct. It is recommended to have a `README.md` file in your repository to explain what the extension is, so create one if you haven't already. + +When you're ready to release, commit your extension's files to the repo and tag your first version: + +```bash +git tag v0.1.0 +git push && git push --tags +``` + +## Publishing on Packagist + +Composer packages are published to a Composer repository, usually [Packagist](https://packagist.org/). You will need an account to proceed. + +If this is the first release you are publishing of your extension, you will need to [submit your package](https://packagist.org/packages/submit) using its public repository URL. If your extension is located on GitHub, this URL will look something like `https://github.com/AUTHOR/NAME.git`. + +### Future Releases + +You can set up Packagist to [auto-update packages](https://packagist.org/about#how-to-update-packages). Then for future releases, all you will need to do with Git is commit, tag, and push it to the remote server. + +## Promoting Your Extension + +You will most likely want to create a discussion on the Flarum Community in the [Extensions tag](https://discuss.flarum.org/t/extensions). Other people can install your extension using the following command: + +```bash +composer require vendor/package +``` \ No newline at end of file diff --git a/versioned_docs/version-1.x/extend/extending-extensions.md b/versioned_docs/version-1.x/extend/extending-extensions.md new file mode 100644 index 000000000..f419436b6 --- /dev/null +++ b/versioned_docs/version-1.x/extend/extending-extensions.md @@ -0,0 +1,125 @@ +# Extending Extensions + +Flarum extensions aren't just for adding features to core: extensions can extend other extensions! + +:::tip + +To learn how to make your extension extensible, see the [relevant documentation](extensibility.md) + +::: + +## Dependencies + +If your extension relies on another extension, you'll want to ensure that: + +- The other extension is installed and enabled before yours can be. +- The other extension can't be disabled while yours is enabled. +- The other extension is booted before your extension. + +Flarum makes this very easy: just add the other extension to your extension's `composer.json`'s `require` section. + +For example, if you were building a new theme for the Flarum Tags extension, your `composer.json` would look like this: + +```json +{ + // ... + "require": { + "flarum/core": "^0.1.0-beta.15", // Since all extensions need to require core. + "flarum/tags": "^0.1.0-beta.15" // This tells Flarum to treat tags as a dependency of your extension. + }, + // ... +} +``` + +## Optional Dependencies + +Sometimes, extension A might want to extend extension B only if extension B is enabled. +In this case, we call B an "Optional Dependency" of A. +For instance, a drafts extension might want to add support for saving private discussion drafts, but only if the private discussion extension is enabled. + +The first step here is detecting whether extension B is enabled. In the frontend, this is easy: if extension B does anything in the frontend, its extension ID will appear as a key in the `flarum.extensions` global object. For instance: + +```js +if ('some-extension-id' in flarum.extensions) { + // do something +} +``` + +In the backend, you'll need to inject an instance of `Flarum\Extension\ExtensionManager`, and use its `isEnabled()` method. For instance: + +```php +extensions = $extensions; + } + + public function someMethod() + { + if ($this->extensions->isEnabled('some-extension-id')) { + // do something. + } + } +} +``` + +Generally, if your extension has optional dependencies, you'll want it to be booted after said optional dependencies. +You can also do this by specifying composer package names (NOT flarum extension IDs) in an array for the `extra.flarum-extension.optional-dependencies` key of your composer.json. + +For instance: + +```json +{ + // ... + "extra": { + "flarum-extension": { + "optional-dependencies": [ + "flarum/tags" + ] + } + }, + // ... +} +``` + +## Importing from Extensions + +In the backend, you can import the classes you need via regular PHP `use` statements: + +```php + { + // Your Extension Code Here +}) + +export { + // Put all the stuff you want to export here. +} +``` diff --git a/versioned_docs/version-1.x/extend/filesystem.md b/versioned_docs/version-1.x/extend/filesystem.md new file mode 100644 index 000000000..26149a64e --- /dev/null +++ b/versioned_docs/version-1.x/extend/filesystem.md @@ -0,0 +1,132 @@ +# Filesystem + +Flarum core integrates with the filesystem to store and serve assets (like compiled JS/CSS or upload logos/favicons) and avatars. + +Extensions can use Flarum's provided utils for their own filesystem interaction and file storage needs. This system is based around [Laravel's filesystem tools](https://laravel.com/docs/8.x/filesystem), which are in turn based on the [Flysystem library](https://github.com/thephpleague/flysystem). + +## Disks + +Filesystem **disks** represent storage locations, and are backed by storage drivers, which we'll cover later. +Flarum core has 2 disks: `flarum-assets` and `flarum-avatars`. + +### Using existing disks + +To access a disk, you'll need to retrieve it from the [Filesystem Factory](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Factory.html). +To do so, you should inject the factory contract in your class, and access the disks you need. + +Let's take a look at core's [`DeleteLogoController`](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/src/Api/Controller/DeleteLogoController.php#L19-L58) for an example: + +```php +settings = $settings; + $this->uploadDir = $filesystemFactory->disk('flarum-assets'); + } + + /** + * {@inheritdoc} + */ + protected function delete(ServerRequestInterface $request) + { + RequestUtil::getActor($request)->assertAdmin(); + + $path = $this->settings->get('logo_path'); + + $this->settings->set('logo_path', null); + + if ($this->uploadDir->exists($path)) { + $this->uploadDir->delete($path); + } + + return new EmptyResponse(204); + } +} +``` + +The object returned by `$filesystemFactory->disk(DISK_NAME)` implements the [Illuminate\Contracts\Filesystem\Cloud](https://laravel.com/api/8.x/Illuminate/Contracts/Filesystem/Cloud.html) interface, and can be used to create/get/move/delete files, and to get the URL to a resource. + +### Declaring new disks + +Some extensions will want to group their resources / uploads onto a custom disk as opposed to using `flarum-assets` or `flarum-avatars`. + +This can be done via the `Filesystem` extender: + +```php +use Flarum\Extend; + +return [ + (new Extend\Filesystem) + ->disk('flarum-uploads', function (Paths $paths, UrlGenerator $url) { + return [ + 'root' => "$paths->public/assets/uploads", + 'url' => $url->to('forum')->path('assets/uploads') + ]; + }); +``` + +Since all disks use the local filesystem by default, you'll need to provide a base path and base URL for the local filesystem. + +The config array can contain other entries supported by [Laravel disk config arrays](https://laravel.com/docs/8.x/filesystem#configuration). The `driver` key should not be provided, and will be ignored. + +## Storage drivers + +Flarum selects the active driver for each disk by checking the `disk_driver.DISK_NAME` key in the [settings repository](settings.md) and [config.php file](../config.md). If no driver is configured, or the configured driver is unavailable, Flarum will default to the `local` driver. + +You can define new storage drivers by implementing the [`Flarum\Filesystem\DriverInterface` interface](https://github.com/flarum/framework/blob/main/framework/core/src/Filesystem/DriverInterface.php#L16), and registering it via the `Filesystem` extender: + +```php +use Flarum\Extend; + +return [ + (new Extend\Filesystem) + ->driver('aws-with-cdn', AwsWithCdnDriver::class); +``` + +Filesystem storage drivers are a very powerful tool that allows you to completely customize file storage locations, attach arbitrary CDNs, and otherwise extend the filesystem / cloud storage integration layer. + +:::danger + +Some drivers might try to index their filesystem every time the driver is instantiated, even if only the `url` method is needed. This can have serious performance implications. In most cases, you'll want to ensure that your driver's `url` method does not ping the remote filesystem. Similarly, the remote filesystem should usually not be accessed until operations are actually executed. + +::: + +## GUI and Admin Configuration + +Flarum does not currently provide a GUI for selecting drivers for disks, or for entering settings for drivers. This might be added in the future. +For now, extensions are responsible for providing a GUI for their disks and drivers. + +As noted [above](#storage-drivers), if your extension provides a GUI for selecting drivers for a disk, it should modify the `disk_driver.DISK_NAME` key in settings. diff --git a/versioned_docs/version-1.x/extend/formatting.md b/versioned_docs/version-1.x/extend/formatting.md new file mode 100644 index 000000000..d4ea23b12 --- /dev/null +++ b/versioned_docs/version-1.x/extend/formatting.md @@ -0,0 +1,42 @@ +# Formatting + +Flarum uses the powerful [s9e TextFormatter](https://github.com/s9e/TextFormatter) library to format posts from plain markup into HTML. You should become familiar with [how TextFormatter works](https://s9etextformatter.readthedocs.io/Getting_started/How_it_works/) before you attempt to extend it. + +In Flarum, post content is formatted with a minimal TextFormatter configuration by default. The bundled **Markdown** and **BBCode** extensions simply enable the respective plugins on this TextFormatter configuration. + +## Configuration + +You can configure the TextFormatter `Configurator` instance, as well as run custom logic during parsing and rendering, using the `Formatter` extender: + +```php +use Flarum\Extend; +use Psr\Http\Message\ServerRequestInterface as Request; +use s9e\TextFormatter\Configurator; +use s9e\TextFormatter\Parser; +use s9e\TextFormatter\Renderer; + +return [ + (new Extend\Formatter) + // Add custom text formatter configuration + ->configure(function (Configurator $config) { + $config->BBCodes->addFromRepository('B'); + }) + // Modify raw text before it is parsed. + // This callback should return the modified text. + ->parse(function (Parser $parser, $context, $text) { + // custom logic here + return $newText; + }) + // Modify the XML to be rendered before rendering. + // This callback should return the new XML. + // For example, in the mentions extension, this is used to + // provide the username and display name of the user being mentioned. + // Make sure that the last $request argument is nullable (or omitted entirely). + ->render(function (Renderer $renderer, $context, $xml, Request $request = null) { + // custom logic here + return $newXml; + }) +]; +``` + +With a good understanding of TextFormatter, this will allow you to achieve anything from simple BBCode tag additions to more complex formatting tasks like Flarum's **Mentions** extension. diff --git a/versioned_docs/version-1.x/extend/forms.md b/versioned_docs/version-1.x/extend/forms.md new file mode 100644 index 000000000..7cf935d17 --- /dev/null +++ b/versioned_docs/version-1.x/extend/forms.md @@ -0,0 +1,114 @@ +# Forms and Requests + +In this article, we'll go over some frontend tools that are available to us for building and managing forms, as well how to send HTTP requests via Flarum. + +## Form Components + +As with any interactive site, you will likely want to include forms in some pages and modals. +Flarum provides some components to make building (and styling!) these forms easier. +Please see the linked API documentation for each of these to learn more about its accepted attrs. + +- The [`flarum/common/components/FieldSet` component](https://api.docs.flarum.org/js/master/class/src/common/components/fieldset.js~fieldset) wraps its children in a HTML fieldset tag, with a legend. +- The [`flarum/common/components/Select` component](https://api.docs.flarum.org/js/master/class/src/common/components/select.js~select) is a stylized select input. +- The [`flarum/common/components/Switch`](https://api.docs.flarum.org/js/master/class/src/common/components/switch.js~switch) and [`flarum/common/components/Checkbox` components](https://api.docs.flarum.org/js/master/class/src/common/components/checkbox.js~checkbox) are stylized checkbox input components. Their `loading` attr can be set to `true` to show a loading indicator. +- The [`flarum/common/components/Button` component](https://api.docs.flarum.org/js/master/class/src/common/components/button.js~button) is a stylized button, and is used frequently throughout Flarum. + +You'll typically want to assign logic for reacting to input changes via Mithril's `on*` attrs, not external listeners (as is common with jQuery or plain JS). For example: + +```jsx +import Component from 'flarum/common/Component'; +import FieldSet from 'flarum/common/components/FieldSet'; +import Button from 'flarum/common/components/Button'; +import Switch from 'flarum/common/components/Switch'; + + +class FormComponent extends Component { + oninit(vnode) { + this.textInput = ""; + this.booleanInput = false; + } + + view() { + return ( +
+
+ this.textInput = e.target.value}> + + this.booleanInput = val}> + +
+ +
+ ) + } + + onsubmit() { + // Some form handling logic here + } +} +``` + +Don't forget to use [translations](i18n.md)! + + +## Streams, bidi, and withAttr + +Flarum provides [Mithril's Stream](https://mithril.js.org/stream.html) as `flarum/common/util/Stream`. +This is a very powerful reactive data structure, but is most commonly used in Flarum as a wrapper for form data. +Its basic usage is: + +```js +import Stream from 'flarum/common/utils/Stream'; + + +const value = Stream("hello!"); +value() === "hello!"; // true +value("world!"); +value() === "world!"; // true +``` + +In Flarum forms, streams are frequently used together with the bidi attr. +Bidi stands for bidirectional binding, and is a common pattern in frontend frameworks. Flarum patches Mithril with the [`m.attrs.bidi` library](https://github.com/tobyzerner/m.attrs. +This abstracts away input processing in Mithril. For instance: + +```jsx +import Stream from 'flarum/common/utils/Stream'; + +const value = Stream(); + +// Without bidi + value(e.target.value)}> + +// With bidi + +``` + +You can also use the `flarum/common/utils/withAttr` util for simplified form processing. `withAttr` calls a callable, providing as an argument some attr of the DOM element tied to the component in question: + +```jsx +import Stream from 'flarum/common/utils/Stream'; +import withAttr from 'flarum/common/utils/withAttr'; + +const value = Stream(); + +// With a stream + + +// With any callable + { + // Some custom logic here +})}> +``` + +## Making Requests + +In our [models](models.md) documentation, you learned how to work with models, and save model creation, changes, and deletion to the database via the Store util, which is just a wrapper around Flarum's request system, which itself is just a wrapper around [Mithril's request system](https://mithril.js.org/request.html). + +Flarum's request system is available globally via `app.request(options)`, and has the following differences from Mithril's `m.request(options)`: + +- It will automatically attach `X-CSRF-Token` headers. +- It will convert `PATCH` and `DELETE` requests into `POST` requests, and attach a `X-HTTP-Method-Override` header. +- If the request errors, it will show an alert which, if in debug mode, can be clicked to show a full error modal. +- You can supply a `background: false` option, which will run the request synchronously. However, this should almost never be done. + +Otherwise, the API for using `app.request` is the same as that for `m.request`. diff --git a/versioned_docs/version-1.x/extend/frontend-pages.md b/versioned_docs/version-1.x/extend/frontend-pages.md new file mode 100644 index 000000000..33ac5f472 --- /dev/null +++ b/versioned_docs/version-1.x/extend/frontend-pages.md @@ -0,0 +1,225 @@ +# Frontend Pages and Resolvers + +As explained in the [Routes and Content](routes.md#frontend-routes) documentation, we can use Mithril's routing system to show different [components](frontend.md#components) for different routes. Mithril allows you to use any component you like, even a Modal or Alert, but we recommend sticking to component classes that inherit the `Page` component. + +## The Page Component + +We provide `flarum/common/components/Page` as a base class for pages in both the `admin` and `forum` frontends. It has a few benefits: + +- Automatically updates [`app.current` and `app.previous` PageState](#pagestate) when switching from one route to another. +- Automatically closes the modal and drawer when switching from one route to another. +- Applies `this.bodyClass` (if defined) to the '#app' HTML element when the page renders. +- It's also good for consistency's sake to use a common base class for all pages. +- If the page's `scrollTopOnCreate` attribute is set to `false` in `oninit`, the page won't be scrolled to the top when changed. +- If the page's `useBrowserScrollRestoration` is set to `false` in `oninit`, the browser's automatic scroll restoration won't be used on that page. + +Page components work just like any other inherited component. For a (very simple) example: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + view() { + return

Hello!

+ } +} +``` + +### Setting Page as Homepage + +Flarum uses a setting to determine which page should be the homepage: this gives admins flexibility to customize their communities. +To add your custom page to the homepage options in Admin, you'll need to extend the `BasicsPage.homePageItems` method with your page's path. + +An example from the [Tags extension](https://github.com/flarum/tags/blob/master/js/src/admin/addTagsHomePageOption.js): + +```js +import { extend } from 'flarum/common/extend'; +import BasicsPage from 'flarum/common/components/BasicsPage'; + +export default function() { + extend(BasicsPage.prototype, 'homePageItems', items => { + items.add('tags', { + path: '/tags', + label: app.translator.trans('flarum-tags.admin.basics.tags_label') + }); + }); +} +``` + +To learn how to set up a path/route for your custom page, see the [relevant documentation](routes.md). + +### Page Titles + +Often, you'll want some custom text to appear in the browser tab's title for your page. +For instance, a tags page might want to show "Tags - FORUM NAME", or a discussion page might want to show the title of the discussion. + +To do this, your page should include calls to `app.setTitle()` and `app.setTitleCount()` in its `oncreate` [lifecycle hook](frontend.md) (or when data is loaded, if it pulls in data from the API). + +For example: + +```js +import Page from 'flarum/common/components/Page'; + + +export default class CustomPage extends Page { + oncreate(vnode) { + super.oncreate(vnode); + + app.setTitle("Cool Page"); + app.setTitleCount(0); + } + + view() { + // ... + } +} + +export default class CustomPageLoadsData extends Page { + oninit(vnode) { + super.oninit(vnode); + + app.store.find("users", 1).then(user => { + app.setTitle(user.displayName()); + app.setTitleCount(0); + }) + } + + view() { + // ... + } +} +``` + +Please note that if your page is [set as the homepage](#setting-page-as-homepage), `app.setTitle()` will clear the title for simplicity. +It should still be called though, to prevent titles from previous pages from carrying over. + +## PageState + +Sometimes, we want to get information about the page we're currently on, or the page we've just come from. +To allow this, Flarum creates (and stores) instances of [`PageState`](https://api.docs.flarum.org/js/master/class/src/common/states/pagestate.js~pagestate) as `app.current` and `app.previous`. +These store: + +- The component class being used for the page +- A collection of data that each page sets about itself. The current route name is always included. + +Data can be set to, and retrieved from, Page State using: + +```js +app.current.set(KEY, DATA); +app.current.get(KEY); +``` + +For example, this is how the Discussion Page makes its [`PostStreamState`](https://api.docs.flarum.org/js/master/class/src/forum/states/poststreamstate.js~poststreamstate) instance globally available. + +You can also check the type and data of a page using `PostStreamState`'s `matches` method. For instance, if we want to know if we are currently on a discussion page: + +```jsx +import IndexPage from 'flarum/forum/components/DiscussionPage'; +import DiscussionPage from 'flarum/forum/components/DiscussionPage'; + +// To just check page type +app.current.matches(DiscussionPage); + +// To check page type and some data +app.current.matches(IndexPage, {routeName: 'following'}); +``` + +## Admin Pages + +See the [Admin Dashboard documentation](admin.md) for more information on tools specifically available to admin pages (and how to override the admin page for your extension). + +## Route Resolvers (Advanced) + +[Advanced use cases](https://mithril.js.org/route.html#advanced-component-resolution) can take advantage of Mithril's [route resolver system](https://mithril.js.org/route.html#routeresolver). +Flarum actually already wraps all its components in the `flarum/common/resolvers/DefaultResolver` resolver. This has the following benefits: + +- It passes a `routeName` attr to the current page, which then provides it to `PageState` +- It assigns a [key](https://mithril.js.org/keys.html#single-child-keyed-fragments) to the top level page component. When the route changes, if the top level component's key has changed, it will be completely rerendered (by default, Mithril does not rerender components when switching from one page to another if both are handled by the same component). + +### Using Route Resolvers + +There are actually 3 ways to set the component / route resolver when registering a route: + +- the `resolver` key can be used to provide an **instance** of a route resolver. This instance should define which component should be used, and hardcode the route name to be passed into it. This instance will be used without any modifications by Flarum. +- The `resolverClass` key AND `component` key can be used to provide a **class** that will be used to instantiate a route resolver, to be used instead of Flarum's default one, as well as the component to use. Its constructor should take 2 arguments: `(component, routeName)`. +- The `component` key can be used alone to provide a component. This will result in the default behavior. + +For example: + +```js +// See above for a custom page example +import CustomPage from './components/CustomPage'; +// See below for a custom resolver example +import CustomPageResolver from './resolvers/CustomPageResolver'; + +// Use a route resolver instance +app.routes['resolverInstance'] = {path: '/custom/path/1', resolver: { + onmatch: function(args) { + if (!app.session.user) return m.route.SKIP; + + return CustomPage; + } +}}; + +// Use a custom route resolver class +app.routes['resolverClass'] = {path: '/custom/path/2', resolverClass: CustomPageResolver, component: CustomPage}; + +// Use the default resolver class (`flarum/common/resolvers/DefaultResolver`) +app.routes['resolverClass'] = {path: '/custom/path/2', component: CustomPage}; +``` + +### Custom Resolvers + +We strongly encourage custom route resolvers to extend `flarum/common/resolvers/DefaultResolver`. +For example, Flarum's `flarum/forum/resolvers/DiscussionPageResolver` assigns the same key to all links to the same discussion (regardless of the current post), and triggers scrolling when using `m.route.set` to go from one post to another on the same discussion page: + +```js +import DefaultResolver from '../../common/resolvers/DefaultResolver'; + +/** + * This isn't exported as it is a temporary measure. + * A more robust system will be implemented alongside UTF-8 support in beta 15. + */ +function getDiscussionIdFromSlug(slug: string | undefined) { + if (!slug) return; + return slug.split('-')[0]; +} + +/** + * A custom route resolver for DiscussionPage that generates the same key to all posts + * on the same discussion. It triggers a scroll when going from one post to another + * in the same discussion. + */ +export default class DiscussionPageResolver extends DefaultResolver { + static scrollToPostNumber: number | null = null; + + makeKey() { + const params = { ...m.route.param() }; + if ('near' in params) { + delete params.near; + } + params.id = getDiscussionIdFromSlug(params.id); + return this.routeName.replace('.near', '') + JSON.stringify(params); + } + + onmatch(args, requestedPath, route) { + if (route.includes('/d/:id') && getDiscussionIdFromSlug(args.id) === getDiscussionIdFromSlug(m.route.param('id'))) { + DiscussionPageResolver.scrollToPostNumber = parseInt(args.near); + } + + return super.onmatch(args, requestedPath, route); + } + + render(vnode) { + if (DiscussionPageResolver.scrollToPostNumber !== null) { + const number = DiscussionPageResolver.scrollToPostNumber; + // Scroll after a timeout to avoid clashes with the render. + setTimeout(() => app.current.get('stream').goToNumber(number)); + DiscussionPageResolver.scrollToPostNumber = null; + } + + return super.render(vnode); + } +} +``` diff --git a/versioned_docs/version-1.x/extend/frontend.md b/versioned_docs/version-1.x/extend/frontend.md new file mode 100644 index 000000000..ddd7385e0 --- /dev/null +++ b/versioned_docs/version-1.x/extend/frontend.md @@ -0,0 +1,431 @@ +# Frontend Development + +This page describes how to make changes to Flarum's user interface. How to add buttons, marquees, and blinking text. 🤩 + +[Remember](/extend/start.md#architecture), Flarum's frontend is a **single-page JavaScript application**. There's no Twig, Blade, or any other kind of PHP template to speak of. The few templates that are present in the backend are only used to render search-engine-optimized content. All changes to the UI need to be made via JavaScript. + +Flarum has two separate frontend applications: + +* `forum`, the public side of your forum where users create discussions and posts. +* `admin`, the private side of your forum where, as an administrator of your forum, you configure your Flarum installation. + +They share the same foundational code, so once you know how to extend one, you know how to extend both. + +:::tip Typings! + +Along with new TypeScript support, we have a [`tsconfig` package](https://www.npmjs.com/package/flarum-tsconfig) available, which you should install as a dev dependency to gain access to our typings. Make sure you follow the instructions in the [package's README](https://github.com/flarum/flarum-tsconfig#readme) to configure typings support. + +::: + +## Transpilation and File Structure + +This portion of the guide will explain the necessary file setup for extensions. Once again, we highly recommend using the [Flarum CLI](https://github.com/flarum/cli) to set up the file structure for you. That being said, you should still read this to understand what's going on beneath the surface. + +Before we can write any JavaScript, we need to set up a **transpiler**. This allows us to use [TypeScript](https://www.typescriptlang.org/) and its magic in Flarum core and extensions. + +In order to do this transpilation, you need to be working in a capable environment. No, not the home/office kind of environment – you can work in the bathroom for all I care! I'm talking about the tools that are installed on your system. You'll need: + +* Node.js and npm ([Download](https://nodejs.org/en/download/)) +* Webpack (`npm install -g webpack`) + +This can be tricky because everyone's system is different. From the OS you're using, to the program versions you have installed, to the user access permissions – I get chills just thinking about it! If you run into trouble, ~~tell him I said hi~~ use [Google](https://google.com) to see if someone has encountered the same error as you and found a solution. If not, ask for help from the [Flarum Community](https://discuss.flarum.org) or on the [Discord chat](https://flarum.org/discord/). + +It's time to set up our little JavaScript transpilation project. Create a new folder in your extension called `js`, then pop in a couple of new files. A typical extension will have the following frontend structure: + +``` +js +├── dist (compiled js is placed here) +├── src +│ ├── admin +│ └── forum +├── admin.js +├── forum.js +├── package.json +├── tsconfig.json +└── webpack.config.js +``` + +### package.json + +```json +{ + "private": true, + "name": "@acme/flarum-hello-world", + "dependencies": { + "flarum-webpack-config": "^1.0.0", + "webpack": "^4.0.0", + "webpack-cli": "^4.0.0" + }, + "devDependencies": { + "flarum-tsconfig": "^1.0.0" + }, + "scripts": { + "dev": "webpack --mode development --watch", + "build": "webpack --mode production" + } +} +``` + +This is a standard JS [package-description file](https://docs.npmjs.com/files/package.json), used by npm and Yarn (Javascript package managers). You can use it to add commands, js dependencies, and package metadata. We're not actually publishing a npm package: this is simply used to collect dependencies. + +Please note that we do not need to include `flarum/core` or any flarum extensions as dependencies: they will be automatically packaged when Flarum compiles the frontends for all extensions. + +### webpack.config.js + +```js +const config = require('flarum-webpack-config'); + +module.exports = config(); +``` + +[Webpack](https://webpack.js.org/concepts/) is the system that actually compiles and bundles all the javascript (and its dependencies) for our extension. +To work properly, our extensions should use the [official flarum webpack config](https://github.com/flarum/flarum-webpack-config) (shown in the above example). + +### tsconfig.json + +```json +{ + // Use Flarum's tsconfig as a starting point + "extends": "flarum-tsconfig", + // This will match all .ts, .tsx, .d.ts, .js, .jsx files in your `src` folder + // and also tells your Typescript server to read core's global typings for + // access to `dayjs` and `$` in the global namespace. + "include": ["src/**/*", "../vendor/flarum/core/js/dist-typings/@types/**/*"], + "compilerOptions": { + // This will output typings to `dist-typings` + "declarationDir": "./dist-typings", + "baseUrl": ".", + "paths": { + "flarum/*": ["../vendor/flarum/core/js/dist-typings/*"] + } + } +} +``` + +This is a standard configuration file to enable support for Typescript with the options that Flarum needs. + +Always ensure you're using the latest version of this file: https://github.com/flarum/flarum-tsconfig#readme. + +Even if you choose not to use TypeScript in your extension, which is supported natively by our Webpack config, it's still recommended to install the `flarum-tsconfig` package and to include this configuration file so that your IDE can infer types for our core JS. + +To get the typings working, you'll need to run `composer update` in your extension's folder to download the latest copy of Flarum's core into a new `vendor` folder. Remember not to commit this folder if you're using a version control system such as Git. + +You may also need to restart your IDE's TypeScript server. In Visual Studio Code, you can press F1, then type "Restart TypeScript Server" and hit ENTER. This might take a minute to complete. + +### admin.js and forum.js + +These files contain the root of our actual frontend JS. You could put your entire extension here, but that would not be well organized. For this reason, we recommend putting the actual +source code in `src`, and having these files just export the contents of `src`. For instance: + +```js +// admin.js +export * from './src/admin'; + +// forum.js +export * from './src/forum'; +``` + +### src + +If following the recommendations for `admin.js` and `forum.js`, we'll want to have 2 subfolders here: one for `admin` frontend code, and one for `forum` frontend code. +If you have components, models, utils, or other code that is shared across both frontends, you may want to create a `common` subfolder and place it there. + +Structure for `admin` and `forum` is identical, so we'll just show it for `forum` here: + +``` +src/forum/ +├── components/ +|-- models/ +├── utils/ +└── index.js +``` + +`components`, `models`, and `utils` are directories that contain files where you can define custom [components](#components), [models](models.md#frontend-models), and reusable util helper functions. +Please note that this is all simply a recommendation: there's nothing forcing you to use this particular file structure (or any other file structure). + +The most important file here is `index.js`: everything else is just extracting classes and functions into their own files. Let's go over a typical `index.js` file structure: + +```js +import { extend, override } from 'flarum/common/extend'; + +// We provide our extension code in the form of an "initializer". +// This is a callback that will run after the core has booted. +app.initializers.add('acme-flarum-hello-world', function(app) { + // Your Extension Code Here + console.log("EXTENSION NAME is working!"); +}); +``` + +We'll go over tools available for extensions below. + +### Importing + +You should familiarize yourself with proper syntax for [importing js modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import), as most extensions larger than a few lines will split their js into multiple files. + +Pretty much every Flarum extension will need to import *something* from Flarum Core. +Like most extensions, core's JS source code is split up into `admin`, `common`, and `forum` folders. You can import the file by prefixing its path in the Flarum core source code with `flarum`. So `admin/components/AdminLinkButton` is available as `flarum/admin/components/AdminLinkButton`, `common/Component` is available as `flarum/common/Component`, and `forum/states/PostStreamState` is available as `flarum/forum/states/PostStreamState`. + +In some cases, an extension may want to extend code from another flarum extension. This is only possible for extensions which explicitly export their contents. + +* `flarum/tags` and `flarum/flags` are currently the only bundled extensions that allow extending their JS. You can import their contents from `flarum/{EXT_NAME}/PATH` (e.g. `flarum/tags/components/TagHero`). +* The process for extending each community extension is different; you should consult documentation for each individual extension. + +### Transpilation + +OK, time to fire up the transpiler. Run the following commands in the `js` directory: + +```bash +npm install +npm run dev +``` + +This will compile your browser-ready JavaScript code into the `js/dist/forum.js` file, and keep watching for changes to the source files. Nifty! + +When you've finished developing your extension (or before a new release), you'll want to run `npm run build` instead of `npm run dev`: this builds the extension in production mode, which makes the source code smaller and faster. + +## Asset Registration + +### JavaScript + +In order for your extension's JavaScript to be loaded into the frontend, we need to tell Flarum where to find it. We can do this using the `Frontend` extender's `js` method. Add it to your extension's `extend.php` file: + +```php +js(__DIR__.'/js/dist/forum.js') +]; +``` + +Flarum will make anything you `export` from `forum.js` available in the global `flarum.extensions['acme-hello-world']` object. Thus, you may choose to expose your own public API for other extensions to interact with. + +:::tip External Libraries + +Only one main JavaScript file per extension is permitted. If you need to include any external JavaScript libraries, either install them with NPM and `import` them so they are compiled into your JavaScript file, or see [Routes and Content](/extend/routes.md) to learn how to add extra `'; + }) +]; +``` + +You can also add content onto your frontend route registrations: + +```php +return [ + (new Extend\Frontend('forum')) + ->route('/users', 'acme.users', function (Document $document, Request $request) { + $document->title = 'Users'; + }) +]; +``` diff --git a/versioned_docs/version-1.x/extend/search.md b/versioned_docs/version-1.x/extend/search.md new file mode 100644 index 000000000..6deab781b --- /dev/null +++ b/versioned_docs/version-1.x/extend/search.md @@ -0,0 +1,213 @@ +# Searching and Filtering + +Flarum treats searching and filtering as parallel but distinct processes. Which process is used to handle a request to a [`List` API endpoint](/extend/api.md#api-endpoints) depends on the query parameters: + +- Filtering is applied when the `filter[q]` query param is omitted. Filters represent **structured** queries: for instance, you might want to only retrieve discussions in a certain category, or users who registered before a certain date. Filtering computes results based entirely on `filter[KEY] = VALUE` query parameters. +- Searching is applied when the `filter[q]` query param is included. Searches represent **unstructured** queries: the user submits an arbitrary string, and data records that "match" it are returned. For instance, you might want to search discussions based on the content of their posts, or users based on their username. Searching computes results based solely on parsing the `filter[q]` query param: all other `filter[KEY] = VALUE` params are ignored when searching. It's important to note that searches aren't entirely unstructured: the dataset being searched can be constrained by gambits (which are very similar to filters, and will be explained later). + +This distinction is important because searches and filters have very different use cases: filters represent *browsing*: that is, the user is passively looking through some category of content. In contrast, searches represent, well, *searching*: the user is actively looking for content based on some criteria. + +Flarum implements searching and filtering via per-model `Searcher` and `Filterer` classes (discussed in more detail below). Both classes accept a [`Flarum\Query\QueryCriteria`](https://api.docs.flarum.org/php/master/flarum/query/querycriteria) instance (a wrapper around the user and query params), and return a [`Flarum\Query\QueryResults`](https://api.docs.flarum.org/php/master/flarum/query/queryresults) instance (a wrapper around an Eloquent model collection). This common interface means that adding search/filter support to models is quite easy. + +One key advantage of this split is that it allows searching to be implemented via an external service, such as ElasticSearch. For larger communities, this can be significantly more performant and accurate. There isn't a dedicated extender for this yet, so for now, replacing the default Flarum search driver requires overriding the container bindings of `Searcher` classes. This is a highly advanced use case; if you're interested in doing this, please reach out on our [community forums](https://discuss.flarum.org/). + +Remember that the [JSON:API schema](https://jsonapi.org/format) is used for all API requests. + +:::tip Reuse Code + +Often, you might want to use the same class as both a `Filter` and a `Gambit` (both explained below). +Your classes can implement both interface; see Flarum core's [`UnreadFilterGambit`](https://github.com/flarum/framework/blob/main/framework/core/src/Discussion/Query/UnreadFilterGambit.php) for an example. + +::: + +:::tip Query Builder vs Eloquent Builder + +`Filter`s, `Gambit`s, filter mutators, and gambit mutators (all explained below) receive a "state" parameter, which wraps + +::: + +## Filtering + +Filtering constrains queries based on `Filters` (highlighted in code to avoid confusion with the process of filtering), which are classes that implement `Flarum\Filter\FilterInterface` and run depending on query parameters. After filtering is complete, a set of callbacks called "filter mutators" run for every filter request. + +When the `filter` method on a `Filterer` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Filter/AbstractFilterer.php#L50-L93)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Filterer` class's `getQuery()` method. +2. We loop through all `filter[KEY] = VALUE` query params. For each of these, any `Filter`s registered to the model whose `getFilterKey()` method matches the query param `KEY` is applied. `Filter`s can be negated by providing the query param as `filter[-KEY] = VALUE`. Whether or not a `Filter` is negated is passed to it as an argument: implementing negation is up to the `Filter`s. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "filter mutators" are applied. These are callbacks that receive the filter state (a wrapper around the query builder and current user) and filter criteria, and perform some arbitrary changes. All "filter mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Filtering for an Existing Model + +Let's say you've added a `country` column to the User model, and would like to filter users by country. We'll need to define a custom `Filter`: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +Note that `FilterState` is a wrapper around the Eloquent builder's underlying Query builder and the current user. + +Also, let's pretend that for some reason, we want to omit any users that have a different country from the current user on ANY filter. +We can use a "filter mutator" for this: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +Now, all we need to do is register these via the Filter extender: + +```php + // Other extenders + (new Extend\Filter(UserFilterer::class)) + ->addFilter(CountryFilter::class) + ->addFilterMutator(OnlySameCountryFilterMutator::class), + // Other extenders +``` + +### Add Filtering to a New Model + +To filter a model that doesn't support filtering, you'll need to create a subclass of `Flarum/Filter/AbstractFilterer` for that model. +For an example, see core's [UserFilterer](https://github.com/flarum/framework/blob/main/framework/core/src/User/Filter/UserFilterer.php). + +Then, you'll need to use that filterer in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +## Searching + +Searching constrains queries by applying `Gambit`s, which are classes that implement `Flarum\Search\GambitInterface`, based on the `filter[q]` query param. +After searching is complete, a set of callbacks called "search mutators" run for every search request. + +When the `search` method on a `Searcher` class is called, the following process takes place ([relevant code](https://github.com/flarum/framework/blob/main/framework/core/src/Search/AbstractSearcher.php#L55-L79)): + +1. An Eloquent query builder instance for the model is obtained. This is provided by the per-model `{MODEL_NAME}Searcher` class's `getQuery()` method. +2. The `filter[q]` param is split by spaces into "tokens". Each token is matched against the model's registered `Gambit`s (each gambit has a `match` method). For any tokens that match a gambit, that gambit is applied, and the token is removed from the query string. Once all regular `Gambit`s have ran, all remaining unmatched tokens are passed to the model's `FullTextGambit`, which implements the actual searching logic. For example if searching discussions, in the `filter[q]` string `'author:1 hello is:hidden' world`, `author:1` and `is:hidden` would get matched by core's Author and Hidden gambits, and `'hello world'` (the remaining tokens) would be passed to the `DiscussionFulltextGambit`. +3. [Sorting](https://jsonapi.org/format/#fetching-sorting), [pagination](https://jsonapi.org/format/#fetching-pagination) are applied. +4. Any "search mutators" are applied. These are callbacks that receive the search state (a wrapper around the query builder and current user) and criteria, and perform some arbitrary changes. All "search mutators" run on any request. +5. We calculate if there are additional matching model instances beyond the query set we're returning for this request, and return this value along with the actual model data, wrapped in a `Flarum\Query\QueryResults` object. + +### Modify Searching for an Existing Model + +Let's reuse the "country" examples we used above, and see how we'd implement the same things for searching: + +```php +getQuery()->where('users.country', $negate ? '!=' : '=', $country); + } +} +``` + +:::warning No Spaces in Gambit Patterns! + +Flarum splits the `filter[q]` string into tokens by splitting it at spaces. +This means that your custom gambits can NOT use spaces as part of their pattern. + +::: + +:::tip AbstractRegexGambit + +All a gambit needs to do is implement `Flarum\Search\GambitInterface`, which receives the search state and a token. +It should return if this gambit applies for the given token, and if so, make whatever mutations are necessary to the +query builder accessible as `$searchState->getQuery()`. + +However, for most gambits, the `AbstractRegexGambit` abstract class (used above) should be used as a base class. +This makes it a lot simpler to match and apply gambits. + +::: + +Similarly, the search mutator we need is almost identical to the filter mutator from before: + +```php +getQuery()->where('users.country', $filterState->getActor()->country); + } +} +``` + +We can register these via the `SimpleFlarumSearch` extender (in the future, the `Search` extender will be used for registering custom search drivers): + +```php + // Other extenders + (new Extend\SimpleFlarumSearch(UserSearcher::class)) + ->addGambit(CountryGambit::class) + ->addSearchMutator(OnlySameCountrySearchMutator::class), + // Other extenders +``` + +### Add Searching to a New Model + +To support searching for a model, you'll need to create a subclass of `Flarum/Search/AbstractSearcher` for that model. +For an example, see core's [UserSearcher](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/UserSearcher.php). + +Then, you'll need to use that searcher in your model's `List` controller. For an example, see core's [ListUsersController](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Controller/ListUsersController.php#L93-L98). + +Every searcher **must** have a fulltext gambit (the logic that actually does the searching). Otherwise, it won't be booted by Flarum, and you'll get an error. +See core's [FulltextGambit for users](https://github.com/flarum/framework/blob/main/framework/core/src/User/Search/Gambit/FulltextGambit.php) for an example. +You can set (or override) the full text gambit for a searcher via the `SimpleFlarumSearch` extender's `setFullTextGambit()` method. + +### Search Drivers + +Coming soon! + +## Frontend Tools + +Coming soon! diff --git a/versioned_docs/version-1.x/extend/service-provider.md b/versioned_docs/version-1.x/extend/service-provider.md new file mode 100644 index 000000000..6640bac28 --- /dev/null +++ b/versioned_docs/version-1.x/extend/service-provider.md @@ -0,0 +1,68 @@ +# Service Provider + +As noted throughout this documentation, Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection. +[Service Providers](https://laravel.com/docs/8.x/providers) allow low-level configuration and modification of the Flarum backend. +The most common use case for service providers is to create, modify, or replace container bindings. +That being said, service providers allow you full access to run whatever logic you need during application boot with access to the container. + +:::caution Advanced Use Only!!! + +Unlike with other extenders, the Service Provider layer is NOT use-case driven, and is NOT considered public API. It is subject to change at any time, without notice or deprecation. This should only be used if you know what you're doing, and the other extenders don't satisfy your use case. + +::: + +## Flarum Boot Process + +To understand service providers, you must first understand the order in which Flarum boots. Most of this happens in [Flarum\Foundation\InstalledSite](https://github.com/flarum/framework/blob/main/framework/core/src/Foundation/InstalledSite.php) + +1. The container and application are initialized, and essential bindings (config, environment, logger) are registered +2. The `register` methods of all core service providers are run. +3. The `extend` methods of all extenders used by all enabled extensions are run. +4. The `extend` methods of all extenders used in the Flarum site's local `extend.php` are run. +5. The `boot` methods of all core service providers are run. + +## Custom Service Providers + +A custom service provider should extend `Flarum\Foundation\AbstractServiceProvider`, and can have a `boot` and a `register` method. For example: + +```php +container->resolving(SomeClass::class, function ($container) { + return new SomeClass($container->make('some.binding')); + }); + } + + public function boot(Container $container) + { + // custom logic here + } +} +``` + +The `register` method will run during step (3) above, and the `boot` method will run during step (5) above. In the `register` method, the container is available via `$this->container`. In the `boot` method, the container (or any other arguments), should be injected via typehinted method arguments. + +Flarum does not currently support Laravel Octane, but some [best practices](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane), like using the `$container` argument inside `bind`, `singleton`, and `resolving` callbacks instead of `$this->container` should be used. See the [Octane documentation](https://laravel.com/docs/8.x/octane#dependency-injection-and-octane) for more information. + +To actually register your custom service provider, you can use the `ServiceProvider` extender in `extend.php`: + +```php +register(CustomServiceProvider::class), + // Other extenders +]; +``` diff --git a/versioned_docs/version-1.x/extend/settings.md b/versioned_docs/version-1.x/extend/settings.md new file mode 100644 index 000000000..5e0f1b492 --- /dev/null +++ b/versioned_docs/version-1.x/extend/settings.md @@ -0,0 +1,93 @@ +# Settings + +At some point while making an extension, you might want to read some of the forum's settings or store certain settings specific to your extension. Thankfully, Flarum makes this very easy. + +## The Settings Repository + +Reading or changing settings can be done using an implementation of the `SettingsRepositoryInterface`. +Because Flarum uses [Laravel's service container](https://laravel.com/docs/8.x/container) (or IoC container) for dependency injection, you don't need to worry about where to obtain such a repository, or how to instantiate one. +Instead, you can rely on the container to instantiate your class and inject the correct dependencies. + +```php +settings = $settings; + } +} +``` + +Great! Now the `SettingsRepositoryInterface` is available through `$this->settings` to our class. + +### Reading Settings + +To read settings, all we have to do is use the repository's `get()` function: + +`$this->settings->get('forum_title')` + +The `get()` function accepts two arguments: + +1. The name of the setting you are trying to read. +2. (Optional) A default value if no value has been stored for such a setting. By default, this will be `null`. + +### Storing Settings + +Storing settings ist just as easy, use the `set()` function: + +`$this->settings->set('forum_title', 'Super Awesome Forum')` + +The `set` function also accepts two arguments: + +1. The name of the setting you are trying to change. +2. The value you want to store for this setting. + +### Other Functions + +The `all()` function returns an array of all known settings. + +The `delete($name)` function lets you remove a named setting. + +## Settings in the Frontend + +### Editing Settings + +To learn more about adding settings through the admin dashboard, see the [relevant documentation](admin.md). +### Accessing Settings + +All settings are available in the `admin` frontend via the `app.data.settings` global. +However, this is not done in the `forum` frontend, as anyone can access it, and you wouldn't want to leak all your settings! (Seriously, that could be a very problematic data breach). + +Instead, if we want to use settings in the `forum` frontend, we'll need to serialize them and send them alongside the initial forum data payload. + +This can be done via the `Settings` extender. For example: + +**extend.php** + +```php +use Flarum\Extend; + +return [ + (new Extend\Settings) + ->serializeToForum('myCoolSetting', 'my.cool.setting.key') + ->serializeToForum('myCoolSettingModified', 'my.cool.setting.key', function ($retrievedValue) { + // This third argument is optional, and allows us to pass the retrieved setting through some custom logic. + // In this example, we'll append a string to it. + + return "My Cool Setting: $retrievedValue"; + }, "default value!"), +] +``` + +Now, the `my.cool.setting.key` setting will be accessible in the frontend as `app.forum.attribute("myCoolSetting")`, and our modified value will be accessible via `app.forum.attribute("myCoolSettingModified")`. diff --git a/versioned_docs/version-1.x/extend/slugging.md b/versioned_docs/version-1.x/extend/slugging.md new file mode 100644 index 000000000..3dc39416b --- /dev/null +++ b/versioned_docs/version-1.x/extend/slugging.md @@ -0,0 +1 @@ +# Model Slugging diff --git a/versioned_docs/version-1.x/extend/start.md b/versioned_docs/version-1.x/extend/start.md new file mode 100644 index 000000000..b73125a7c --- /dev/null +++ b/versioned_docs/version-1.x/extend/start.md @@ -0,0 +1,153 @@ +# Getting Started + +Want to build a Flarum extension? You've come to the right place! This document will take you through some essential concepts, after which you'll build your first Flarum extension from scratch. + +## Architecture + +In order to understand how to extend Flarum, first we need to understand a bit about how Flarum is built. + +Be aware that Flarum uses some _modern_ languages and tools. If you've only ever built WordPress plugins before, you might feel a bit out of your depth! That's OK — this is a great time to learn cool new things and extend your skillset. However, we would advise that you become somewhat familiar with the technologies described below before proceeding. + +Flarum is made up of three layers: + +* First, there is the **backend**. This is written in [object-oriented PHP](https://laracasts.com/series/object-oriented-bootcamp-in-php), and makes use of a wide array of [Laravel](https://laravel.com/) components and other packages via [Composer](https://getcomposer.org/). You'll also want to familiarize yourself with the concept of [Dependency Injection](https://laravel.com/docs/8.x/container), which is used throughout our backend. + +* Second, the backend exposes a **public API** which allows frontend clients to interface with your forum's data. This is built according to the [JSON:API specification](https://jsonapi.org/). + +* Finally, there is the default web interface which we call the **frontend**. This is a [single-page application](https://en.wikipedia.org/wiki/Single-page_application) which consumes the API. It's built with a simple React-like framework called [Mithril.js](https://mithril.js.org). + +Extensions will often need to interact with all three of these layers to make things happen. For example, if you wanted to build an extension that adds custom fields to user profiles, you would need to add the appropriate database structures in the **backend**, expose that data in the **public API**, and then display it and allow users to edit it on the **frontend**. + +So... how do we extend these layers? + +## Extenders + +In order to extend Flarum, we will be using a concept called **extenders**. Extenders are *declarative* objects that describe in plain terms the goals you are trying to achieve (such as adding a new route to your forum, or executing some code when a new discussion was created). + +Every extender is different. However, they will always look somewhat similar to this: + +```php +// Register a JavaScript and a CSS file to be delivered with the forum frontend +(new Extend\Frontend('forum')) + ->js(__DIR__.'/forum-scripts.js') + ->css(__DIR__.'/forum-styles.css') +``` + +You first create an instance of the extender, and then call methods on it for further configuration. All of these methods return the extender itself, so that you can achieve your entire configuration just by chaining method calls. + +To keep things consistent, we use this concept of extenders in both the backend (in PHP land) and the frontend (in JavaScript land). _Everything_ you do in your extension should be done via extenders, because they are a **guarantee** we are giving to you that a future minor release of Flarum won't break your extension. + +All of the extenders currently available to you from Flarum's core can be found in the [`Extend` namespace](https://github.com/flarum/framework/blob/main/framework/core/src/Extend) [(PHP API documentation)](https://api.docs.flarum.org/php/master/flarum/extend) Extensions may also offer their [own extenders](extensibility.md#custom-extenders). + +## Hello World + +Want to see an extender in action? The `extend.php` file in the root of your Flarum installation is the easiest way to register extenders just for your site. It should return an array of extender objects. Pop it open and add the following: + +```php +content(function (Document $document) { + $document->head[] = ''; + }) +]; +``` + +Now pay your forum a visit for a pleasant (albeit extremely obtrusive) greeting. 👋 + +For simple site-specific customizations – like adding a bit of custom CSS/JavaScript, or integrating with your site's authentication system – the `extend.php` file in your forum's root is great. But at some point, your customization might outgrow it. Or maybe you have wanted to build an extension to share with the community from the get-go. Time to build an extension! + +## Extension Packaging + +[Composer](https://getcomposer.org) is a dependency manager for PHP. It allows applications to easily pull in external code libraries and makes it easy to keep them up-to-date so that security and bug fixes are propagated rapidly. + +As it turns out, every Flarum extension is also a Composer package. That means someone's Flarum installation can "require" a certain extension and Composer will pull it in and keep it up-to-date. Nice! + +During development, you can work on your extensions locally and set up a [Composer path repository](https://getcomposer.org/doc/05-repositories.md#path) to install your local copy. Create a new `packages` folder in the root of your Flarum installation, and then run this command to tell Composer that it can find packages in here: + +```bash +composer config repositories.0 path "packages/*" +``` + +Now let's start building our first extension. Make a new folder inside `packages` for your extension called `hello-world`. We'll put two files in it: `extend.php` and `composer.json`. These files serve as the heart and soul of the extension. + +### extend.php + +The `extend.php` file is just like the one in the root of your site. It will return an array of extender objects that tell Flarum what you want to do. For now, just move over the `Frontend` extender that you had earlier. + +### composer.json + +We need to tell Composer a bit about our package, and we can do this by creating a `composer.json` file: + +```json +{ + "name": "acme/flarum-hello-world", + "description": "Say hello to the world!", + "type": "flarum-extension", + "require": { + "flarum/core": "^1.0.0" + }, + "autoload": { + "psr-4": {"Acme\\HelloWorld\\": "src/"} + }, + "extra": { + "flarum-extension": { + "title": "Hello World", + "icon": { + "name": "fas fa-smile", + "backgroundColor": "#238c59", + "color": "#fff" + } + } + } +} +``` + +* **name** is the name of the Composer package in the format `vendor/package`. + * You should choose a vendor name that’s unique to you — your GitHub username, for example. For the purposes of this tutorial, we’ll assume you’re using `acme` as your vendor name. + * You should prefix the `package` part with `flarum-` to indicate that it’s a package specifically intended for use with Flarum. + +* **description** is a short one-sentence description of what the extension does. + +* **type** MUST be set to `flarum-extension`. This ensures that when someone "requires" your extension, it will be identified as such. + +* **require** contains a list of your extension's own dependencies. + * You'll want to specify the version of Flarum that your extension is compatible with here. + * This is also the place to list other Composer libraries your code needs to work. + +* **autoload** tells Composer where to find your extension's classes. The namespace in here should reflect your extensions' vendor and package name in CamelCase. + +* **extra.flarum-extension** contains some Flarum-specific information, like your extension's display name and how its icon should look. + * **title** is the display name of your extension. + * **icon** is an object which defines your extension's icon. The **name** property is a [Font Awesome icon class name](https://fontawesome.com/icons). All other properties are used as the `style` attribute for your extension's icon. + +See [the composer.json schema](https://getcomposer.org/doc/04-schema.md) documentation for information about other properties you can add to `composer.json`. + +:::info [Flarum CLI](https://github.com/flarum/cli) + +Use the CLI to automatically create your extension's scaffolding: +```bash +$ flarum-cli init +``` + +::: + +### Installing Your Extension + +The final thing we need to do to get up and running is to install your extension. Navigate to the root directory of your Flarum install and run the following command: + +```bash +composer require acme/flarum-hello-world *@dev +``` + +Once that's done, go ahead and fire 'er up on your forum's Administration page, then navigate back to your forum. + +*whizzing, whirring, metal clunking* + +Woop! Hello to you too, extension! + +We're making good progress. We've learned how to set up our extension and use extenders, which opens up a lot of doors. Read on to learn how to extend Flarum's frontend. diff --git a/versioned_docs/version-1.x/extend/static-code-analysis.md b/versioned_docs/version-1.x/extend/static-code-analysis.md new file mode 100644 index 000000000..28e6c4aa7 --- /dev/null +++ b/versioned_docs/version-1.x/extend/static-code-analysis.md @@ -0,0 +1,86 @@ +# Static Code Analysis + +Static code analysis is the process of analyzing the source code against a set of rules to find bugs, code smells, and security vulnerabilities. This is a great way to improve the quality of your code and to find potential issues before they are deployed to production. An example is validating the typings of a function to ensure that the function is called with the correct arguments. + +Flarum provides a static code analysis package based on [PHPStan](https://phpstan.org/) that can be added to your extension. In this guide, we will show you how to add the package to your extension and how to run the analysis. + +## Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update the infrastructure for phpstan to your code: + +```bash +$ flarum-cli infra phpstan +``` + +::: + +First you need to require the `flarum/phpstan` package in your extension. You can do this by running the following command in the root of our extension: + +```bash +composer require --dev flarum/phpstan:^1.0 +``` + +Next, you need to create a `phpstan.neon` file in the root of your extension. This file contains [the configuration for PHPStan](https://phpstan.org/config-reference). You can copy the following configuration into the file: + +```neon +includes: + - vendor/flarum/phpstan/extension.neon + +parameters: + # The level will be increased in Flarum 2.0 + level: 5 + paths: + - src + - extend.php + excludePaths: + - *.blade.php + checkMissingIterableValueType: false + databaseMigrationsPath: ['migrations'] +``` + +Finally, you need to add the following script to your `composer.json` file: + +```json +{ + "scripts": { + "analyse:phpstan": "phpstan analyse", + "clear-cache:phpstan": "phpstan clear-result-cache" + }, + "scripts-descriptions": { + "analyse:phpstan": "Run static analysis" + } +} +``` + +## Running the analysis + +To run the analysis, you can run the following command in the root of your extension: + +```bash +composer analyse:phpstan +``` + +If you want to clear the cache before running the analysis, you can run the following command: + +```bash +composer clear-cache:phpstan && composer analyse:phpstan +``` + +## GitHub Actions + +You can also run the analysis using GitHub Actions. Checkout the page on [GitHub Actions](github-actions.md) for more information. + +## Tips + +### Extended model attribute types + +PHPStan needs to be able to determine the type of an attribute added to an existing model. To do this you can use the `Extend\Model(...)->cast(...)` method. + +For example, if your extension were to add a `is_cool` attribute to the `User` model, you can use [attribute casting](https://laravel.com/docs/8.x/eloquent-mutators#attribute-casting) to explicitly define the attribute as boolean. The `flarum/phpstan` package will automatically detect this and communicate it to PHPStan. + +```php +(new Extend\Model(User::class)) + ->cast('is_cool', 'bool'), +``` diff --git a/versioned_docs/version-1.x/extend/testing.md b/versioned_docs/version-1.x/extend/testing.md new file mode 100644 index 000000000..6a9b32402 --- /dev/null +++ b/versioned_docs/version-1.x/extend/testing.md @@ -0,0 +1,570 @@ +# Testing + +Automated testing ensures that your extension performs as you expect it to, helps avoid introducing new bugs or regressions, and saves time on manual testing. +Flarum currently provides tooling for automated backend unit and integration tests, and we plan to release support for frontend unit testing and E2E testing in the future. + +## Backend Tests + +The `flarum/testing` library is used by core and some bundled extensions for automated unit and integration tests. +It is essentially a collection of utils that allow testing Flarum core and extensions with PHPUnit. + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update backend testing infrastructure to your code: + +```bash +$ flarum-cli infra backendTesting +``` + +::: + +```bash +composer require --dev flarum/testing:^1.0 +``` + +Then, you will need to set up a file structure for tests, and add PHPUnit configuration: + +``` +tests +├── fixtures (put any files needed by your tests here (blade templates, images, etc)) +├── integration +│ ├── setup.php (code below) +│ └── PUT INTEGRATION TESTS HERE (organizing into folder is generally a good idea) +├── unit +│ ├── PUT UNIT TESTS HERE +├── phpunit.integration.xml (code below) +└── phpunit.unit.xml (code below) +``` + +#### phpunit.integration.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for integration tests. You can tweak this as needed, but keep `backupGlobals`, `backupStaticAttributes`, and `processIsolation` unchanged. + +```xml + + + + + + + ./integration + + + +``` + +#### phpunit.unit.xml + +This is just an example [phpunit config file](https://phpunit.readthedocs.io/en/9.3/configuration.html) for unit tests. You can tweak this as needed. + +```xml + + + + + + + ./unit + + + + + + +``` + +#### setup.php + +This script will be run to set up a testing database / file structure. + +```php +run(); +``` + +#### composer.json Modifications + +We will also want to add scripts to our `composer.json`, so that we can run our test suite via `composer test`. Add some variant of the following to your `composer.json`: + +```json +"scripts": { + "test": [ + "@test:unit", + "@test:integration" + ], + "test:unit": "phpunit -c tests/phpunit.unit.xml", + "test:integration": "phpunit -c tests/phpunit.integration.xml", + "test:setup": "@php tests/integration/setup.php" +}, +"scripts-descriptions": { + "test": "Runs all tests.", + "test:unit": "Runs all unit tests.", + "test:integration": "Runs all integration tests.", + "test:setup": "Sets up a database for use with integration tests. Execute this only once." +} +``` + +#### GitHub Testing Workflow + +To run tests on every commit and pull request, check out the [GitHub Actions](github-actions.md) page. + +--- + +Now that we have everything in place, we need to set up our testing site for integration tests. For this, we will need a MySQL or MariaDb instance, and a place to store testing files. + +Testing database information is configured via the `DB_HOST` (defaults to `localhost`), `DB_PORT` (defaults to `3306`), `DB_DATABASE` (defaults to `flarum_test`), `DB_USERNAME` (defaults to `root`), `DB_PASSWORD` (defaults to `root`), and `DB_PREFIX` (defaults to `''`) environmental variables. The testing tmp directory path is configured via the `FLARUM_TEST_TMP_DIR_LOCAL` or `FLARUM_TEST_TMP_DIR` environmental variables, with the former taking precedence over the latter. If neither are provided, a `tmp` directory will be created in the `vendor` folder of your extension's local install. + +Now that we've provided the needed information, all we need to do is run `composer test:setup` in our extension's root directory, and we have our testing environment ready to go! + +Since [(almost)](https://github.com/flarum/framework/blob/4ecd9a9b2ff0e9ba42bb158f3f83bb3ddfc10853/framework/core/tests/integration/api/discussions/ListWithFulltextSearchTest.php#L29-L45) all database operations in integration tests are run in transactions, developers working on multiple extensions will generally find it more convenient to use one shared database and tmp directory for testing all their extensions. To do this, set the database config and `FLARUM_TEST_TMP_DIR` environmental variables in your `.bashrc` or `.bash_profile` to the path you want to use, and run the setup script for any one extension (you'll still want to include the setup file in every repo for CI testing via GitHub Actions). You should then be good to go for any Flarum extension (or core). + +### Using Integration Tests + +Flarum's integration test utils are contained in the `Flarum\Testing\integration\TestCase` class. It: + +- Boots (and makes available) an instance of the Flarum application. +- Allows pre-populating the database, enabling extensions, and adding extenders. +- Runs all database changes in transactions, so your test database retains the default post-installation state. +- Allows sending requests through the middleware stack to test HTTP endpoints. + +Your testcase classes should extend this class. + +#### Test Case Setup + +There are several important utilities available for your test cases: + +- The `setting($key, $value)` method allows you to override settings before the app has booted. This is useful if your boot process has logic depending on settings (e.g. which driver to use for some system). +- Similarly, the `config($key, $value)` method allows you to override config.php values before the app has booted. You can use dot-delimited keys to set deep-nested values in the config array. +- The `extension($extensionId)` method will take Flarum IDs of extensions to enable as arguments. Your extension should always call this with your extension's ID at the start of test cases, unless the goal of the test case in question is to confirm some behavior present without your extension, and compare that to behavior when your extension is enabled. If your extension is dependent on other extensions, make sure they are included in the composer.json `require` field (or `require-dev` for [optional dependencies](extending-extensions.md)), and also list their composer package names when calling `extension()`. Note that you must list them in a valid order. +- The `extend($extender)` method takes instances of extenders as arguments, and is useful for testing extenders introduced by your extension for other extensions to use. +- The `prepareDatabase()` method allow you to pre-populate your database. This could include adding users, discussions, posts, configuring permissions, etc. Its argument is an associative array that maps table names to arrays of [record arrays](https://laravel.com/docs/8.x/queries#insert-statements). + +If your test case needs users beyond the default admin user, you can use the `$this->normalUser()` method of the `Flarum\Testing\integration\RetrievesAuthorizedUsers` trait. + +:::warning + +The `TestCase` class will boot a Flarum instance the first time its `app()` method is called. Any uses of `prepareDatabase`, `extend`, or `extension` after this happens will have no effect. Make sure you have done all the setup you need in your test case before calling `app()`, or `database()`, `server()`, or `send()`, which call `app()` implicitly. If you need to make database modifications after the app has booted, you can use the regular Eloquent save method, or the `Illuminate\Database\ConnectionInterface` instance obtained via calling the `database()` method. + +::: + +Of course, since this is all based on PHPUnit, you can use the `setUp()` methods of your test classes for common setup tasks. + +For example: + +```php +setting('my.custom.setting', true); + + // Let's assume our extension depends on tags. + // Note that tags will need to be in your extension's composer.json's `require-dev`. + // Also, make sure you include the ID of the extension currently being tested, unless you're + // testing the baseline without your extension. + $this->extension('flarum-tags', 'my-cool-extension'); + + // Note that this input isn't validated: make sure you're populating with valid, representative data. + $this->prepareDatabase([ + 'users' => [ + $this->normalUser() // Available for convenience. + ], + 'discussions' => [ + ['id' => 1, 'title' => 'some title', 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 1, 'first_post_id' => 1, 'comment_count' => 1] + ], + 'posts' => [ + ['id' => 1, 'number' => 1, 'discussion_id' => 1, 'created_at' => Carbon::now(), 'user_id' => 1, 'type' => 'comment', 'content' => '

something

'] + ] + ]); + + // Most test cases won't need to test extenders, but if you want to, you can. + $this->extend((new CoolExtensionExtender)->doSomething('hello world')); + } + + /** + * @test + */ + public function some_phpunit_test_case() + { + // ... + } + + // ... +} +``` + +#### Sending Requests + +A common application of automated testing is pinging various HTTP endpoints with various data, authenticated as different users. +You can use this to ensure that: + +- Users can't access content they're not supported to access. +- Permission-based create/edit/delete operations perform as expected. +- The type and schema of data returned is correct. +- Some desired side effect is applied when pinging an API. +- The basic API operations needed by your extension aren't erroring, and don't break when you make changes. + +`TestCase` provides several utilities: + +- The `request()` method constructs a `Psr\Http\Message\ServerRequestInterface` implementing object from a path, a method, and some options, which can be used for authentication, attaching cookies, or configuring the JSON request body. See the [method docblock](https://github.com/flarum/testing/blob/main/src/integration/TestCase.php) for more information on available options. +- Once you've created a request instance, you can send it (and get a response object back) via the `send()` method. + +For example: + + + +```php +send( + $this->request('GET', '/api/users', ['authenticatedAs' => 1]) + ->withQueryParams(['filter' => ['q' => 'john group:1'], 'sort' => 'username']) + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + /** + * @test + */ + public function can_create_user() + { + $response = $this->send( + $this->request( + 'POST', + '/api/users', + [ + 'authenticatedAs' => 1, + 'json' => [ + 'data' => [ + 'attributes' => [ + 'username' => 'test', + 'password' => 'too-obscure', + 'email' => 'test@machine.local' + ] + ] + ] + ] + ) + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + // ... +} +``` + +:::caution + +If you want to send query parameters in a GET request, you can't include them in the path; you'll need to add them afterwards with the `withQueryParams` method. + +::: + +:::caution + +This is an extreme edge case, but note that MySQL does not update the fulltext index in transactions, so the standard approach won't work if you're trying to test a modified fulltext query. See [core's approach](https://github.com/flarum/framework/blob/main/framework/core/tests/integration/extenders/SimpleFlarumSearchTest.php) for an example of a workaround. + +::: + +#### Console Tests + +If you want to test custom console commands, you can extend `Flarum\Testing\integration\ConsoleTestCase` (which itself extends the regular `Flarum\Testing\integration\TestCase`). It provides 2 useful methods: + +- `$this->console()` returns an instance of `Symfony\Component\Console\Application` +- `$this->runCommand()` takes an array that will be wrapped in `Symfony\Component\Console\Input\ArrayInput`, and run. See the [Symfony code docblock](https://github.com/symfony/console/blob/5.x/Input/ArrayInput.php#L22) for more information. + +For example: + +```php + 'some:command', // The command name, equivalent of `php flarum some:command` + 'foo' => 'bar', // arguments + '--lorem' => 'ipsum' // options + ]; + + $this->assertEquals('Some Output.', $this->runCommand($input)); + } +} +``` + +### Using Unit Tests + +Unit testing in Flarum uses [PHPUnit](https://phpunit.de/getting-started/phpunit-9.html) and so unit testing in flarum is much like any other PHP application. You can find [general tutorials on testing](https://www.youtube.com/watch?v=9-X_b_fxmRM) if you're also new to php. + +When writing unit tests in Flarum, here are some helpful tips. + +#### Mocking Flarum Services + +Unlike the running app, or even integration tests, there is no app/container/etc to inject service instances into our classes. Now all the useful settings, or helpers your extension use require a _mock_ . We want to limit mocking to just the key services, supporting only the minimum interactions needed to test the contract of our individual functions. + +```php + public function setUp(): void + { + parent::setUp(); + // example - if our setting needs settings, we can mock the settings repository + $settingsRepo = m::mock(SettingsRepositoryInterface::class); + // and then control specific return values for each setting key + $settingsRepo->shouldReceive('get')->with('some-plugin-key')->andReturn('some-value-useful-for-testing'); + // construct your class under test, passing mocked services as needed + $this->serializer = new YourClassUnderTest($settingsRepo); + } +``` + +Some aspects require more mocks. If you're validating authorization interactions for instance you might need to mock your users `User::class` and the request's method that provides them as well! + +``` + $this->actor = m::mock(User::class); + $request = m::mock(Request::class)->makePartial(); + $request->shouldReceive('getAttribute->getActor')->andReturn($this->actor); + $this->actor->shouldReceive('SOME PERMISSION')->andReturn(true/false); +``` + +NOTE: If you find your extension needs _lots and lots_ of mocks, or mocks that feel unrelated, it might be an opportunity to simplify your code, perhaps moving key logic into their own smaller functions (that dont require mocks). + +## Frontend Tests + +### Setup + +:::tip [Flarum CLI](https://github.com/flarum/cli) + +You can use the CLI to automatically add and update frontend testing infrastructure to your code: + +```bash +$ flarum-cli infra frontendTesting +``` + +::: + +First, you need to install the Jest config dev dependency: + +```bash +$ yarn add --dev @flarum/jest-config +``` + +Then, add the following to your `package.json`: + +```json +{ + "type": "module", + "scripts": { + ..., + "test": "yarn node --experimental-vm-modules $(yarn bin jest)" + } +} +``` + +Rename `webpack.config.js` to `webpack.config.cjs`. This is necessary because Jest doesn't support ESM yet. + +Create a `jest.config.cjs` file in the root of your extension: + +```js +module.exports = require('@flarum/jest-config')(); +``` + +If you are using TypeScript, create tsconfig.test.json with the following content: + +```json +{ + "extends": "./tsconfig.json", + "include": ["tests/**/*"], + "files": ["../../../node_modules/@flarum/jest-config/shims.d.ts"] +} +``` + +Then, you will need to set up a file structure for tests: + +``` +js +├── dist +├── src +├── tests +│ ├── unit +│ │ └── functionTest.test.js +│ ├── integration +│ │ └── componentTest.test.js +├── package.json +├── tsconfig.json +├── tsconfig.test.json +├── jest.config.cjs +└── webpack.config.cjs +``` + +#### GitHub Testing Workflow + +To run tests on every commit and pull request, check out the [GitHub Actions](github-actions.md) page. + +### Using Unit Tests + +Like any other JS project, you can use Jest to write unit tests for your frontend code. Checkout the [Jest docs](https://jestjs.io/docs/using-matchers) for more information on how to write tests. + +Here's a simple example of a unit test fo core's `abbreviateNumber` function: + +```ts +import abbreviateNumber from '../../../../src/common/utils/abbreviateNumber'; + +test('does not change small numbers', () => { + expect(abbreviateNumber(1)).toBe('1'); +}); + +test('abbreviates large numbers', () => { + expect(abbreviateNumber(1000000)).toBe('1M'); + expect(abbreviateNumber(100500)).toBe('100.5K'); +}); + +test('abbreviates large numbers with decimal places', () => { + expect(abbreviateNumber(100500)).toBe('100.5K'); + expect(abbreviateNumber(13234)).toBe('13.2K'); +}); +``` + +### Using Integration Tests + +Integration tests are used to test the components of your frontend code and the interaction between different components. For example, you might test that a page component renders the correct content based on certain parameters. + +Here's a simple example of an integration test for core's `Alert` component: + +```ts +import Alert from '../../../../src/common/components/Alert'; +import m from 'mithril'; +import mq from 'mithril-query'; +import { jest } from '@jest/globals'; + +describe('Alert displays as expected', () => { + it('should display alert messages with an icon', () => { + const alert = mq(m(Alert, { type: 'error' }, 'Shoot!')); + expect(alert).toContainRaw('Shoot!'); + expect(alert).toHaveElement('i.icon'); + }); + + it('should display alert messages with a custom icon when using a title', () => { + const alert = mq(Alert, { type: 'error', icon: 'fas fa-users', title: 'Woops..' }); + expect(alert).toContainRaw('Woops..'); + expect(alert).toHaveElement('i.fas.fa-users'); + }); + + it('should display alert messages with a title', () => { + const alert = mq(m(Alert, { type: 'error', title: 'Error Title' }, 'Shoot!')); + expect(alert).toContainRaw('Shoot!'); + expect(alert).toContainRaw('Error Title'); + expect(alert).toHaveElement('.Alert-title'); + }); + + it('should display alert messages with custom controls', () => { + const alert = mq(Alert, { type: 'error', controls: [m('button', { className: 'Button--test' }, 'Click me!')] }); + expect(alert).toHaveElement('button.Button--test'); + }); +}); + +describe('Alert is dismissible', () => { + it('should show dismiss button', function () { + const alert = mq(m(Alert, { dismissible: true }, 'Shoot!')); + expect(alert).toHaveElement('button.Alert-dismiss'); + }); + + it('should call ondismiss when dismiss button is clicked', function () { + const ondismiss = jest.fn(); + const alert = mq(Alert, { dismissible: true, ondismiss }); + alert.click('.Alert-dismiss'); + expect(ondismiss).toHaveBeenCalled(); + }); + + it('should not be dismissible if not chosen', function () { + const alert = mq(Alert, { type: 'error', dismissible: false }); + expect(alert).not.toHaveElement('button.Alert-dismiss'); + }); +}); +``` + +#### Methods + +These are the custom methods that are available for mithril component tests: +* **`toHaveElement(selector)`** - Checks if the component has an element that matches the given selector. +* **`toContainRaw(content)`** - Checks if the component HTML contains the given content. + +To negate any of these methods, simply prefix them with `not.`. For example, `expect(alert).not.toHaveElement('button.Alert-dismiss');`. For more information, check out the [Jest docs](https://jestjs.io/docs/using-matchers). For example you may need to check how to [mock functions](https://jestjs.io/docs/mock-functions), or how to use `beforeEach` and `afterEach` to set up and tear down tests. + + + +## E2E Tests + +Coming Soon! diff --git a/versioned_docs/version-1.x/extend/theme.md b/versioned_docs/version-1.x/extend/theme.md new file mode 100644 index 000000000..1b6b6c309 --- /dev/null +++ b/versioned_docs/version-1.x/extend/theme.md @@ -0,0 +1,28 @@ +# Themes + +Flarum "themes" are just extensions. Typically, you'll want to use the `Frontend` extender to register custom [Less](https://lesscss.org/#overview) and JS. +Of course, you can use other extenders too: for example, you might want to support settings to allow configuring your theme. + +You can indicate that your extension is a theme by setting the "extra.flarum-extension.category" key to "theme". For example: + +```json +{ + // other fields + "extra": { + "flarum-extension": { + "category": "theme" + } + } + // other fields +} +``` + +All this will do is show your extension in the "theme" section in the admin dashboard extension list. + +## Less Variable Customization + +You can define new Less variables in your extension's Less files. There currently isn't an extender to modify Less variable values in the PHP layer, but this is planned for future releases. + +## Switching Between Themes + +Flarum doesn't currently have a comprehensive system that would support switching between themes. This is planned for future releases. diff --git a/versioned_docs/version-1.x/extend/update-1_0.md b/versioned_docs/version-1.x/extend/update-1_0.md new file mode 100644 index 000000000..5fb57b004 --- /dev/null +++ b/versioned_docs/version-1.x/extend/update-1_0.md @@ -0,0 +1,261 @@ +# Updating For 1.0 + +Flarum version 1.0 is the long-awaited stable release! This release brings a number of refactors, cleanup, and small improvements that should make your Flarum experience just a bit better! + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Full Stack + +### Translations and transChoice + +#### Background + +Historically, Flarum has used Symfony for backend translations, and a port for frontend translations to keep format consistent. There are a few limitations to this approach though: + +- Developers need to decide between using `trans` or `transChoice` for pluralization +- The pluralization format is proprietary to Symfony +- We have to maintain the JS port ourselves +- Keys for values provided to backend translations need to be wrapped in curly braces. (e.g. `$this->translator->trans('some.translation', ['{username}' => 'Some Username!'])`). +- There's no support for complex applications (nested pluralization, non-number-based selection) +- As a result of the previous point, genderization is impossible. And that's kinda important for a lot of languages. + +### New System + +In v5, Symfony dropped their proprietary `transChoice` system in favor of the more-or-less standard [ICU MessageFormat](https://symfony.com/doc/5.2/translation/message_format.html). This solves pretty much every single one of the aforementioned issues. In this release, Flarum will be fully switching to ICU MessageFormat as well. What does this mean for extensions? + +- `transChoice` should not be used at all; instead, the variable passed for pluralization should be included in the data. +- Keys for backend translations no longer need to be surrounded by curly braces. +- Translations can now use the [`select` and `plural`](https://symfony.com/doc/5.2/translation/message_format.html) formatter syntaxes. For the `plural` formatter, the `offset` parameter and `#` magic variables are supported. +- These `select` and `plural` syntaxes can be nested to arbitrary depth. This is often a bad idea though (beyond, say, 2 levels), as things can get unnecessarily complex. + +No change to translation file naming is necessary (Symfony docs say that an `+intl-icu` suffix is necessary, but Flarum will now interpret all translation files as internationalized). + +#### Future Changes + +In the future, this will serve as a basis for additional features: + +- Translator preprocessors will allow extensions to modify arguments passed to translations. This will enable genderization (extensions could automatically extract a gender field from any objects of type "user" passed in). +- We could support internationalized "magic variables" for numbers: currently, `one` is supported, but others (`few`, `many`, etc) currently aren't. +- We could support ordinal formatting in additional to just plural formatting. + +#### Changes Needed in Extensions + +The `transChoice` methods in the frontend and backend have been removed. +The `trans` method should always be used for translating, regardless of pluralization. +If a translation requires pluralization, make sure you pass in the controlling variable as one of the arguments. + +In the frontend, code that looked like this: + +```js +app.translator.transChoice('some-translation', guestCount, {host: hostName}); +``` + +should be changed to: + +```js +// This uses ES6 key-property shorthand notation. {guestCount: guestCount} is equivalent to {guestCount} +app.translator.trans('some-translation', {host: hostName, guestCount }); +``` + +Similarly, in the backend, + +```php +$translator->transChoice('some-translation', $guestCount, ['{host}' => $hostName]); +``` + +should be changed to: + +```php +$translator->trans('some-translation', ['host' => $hostName, 'guestCount' => $guestCount]); +``` + +Note that in the backend, translation keys were previously wrapped in curly braces. +This is no longer needed. + +#### Changes Needed in Translations + +Translations that aren't using pluralization don't need any changes. + +Pluralized translations should be changed as follows: + +`For {count} minute|For {count} minutes` + +to + +`{count, plural, one {For # minute} other {For # minutes}}` + +Note that in this example, `count` is the variable that controls pluralization. If a different variable were used (such as guestCount in the example above), this would look like: + +`{guestCount, plural, one {For # minute} other {For # minutes}}` + +See [our i18n docs](i18n.md) for more information. + +### Permissions Changes + +For a long time, the `viewDiscussions` and `viewUserList` permissions have been confusing. Despite their names: + +- `viewDiscussions` controls viewing both discussions and users. +- `viewUserList` controls searching users, not viewing user profiles. + +To clear this up, in v1.0, these permissions have been renamed to `viewForum` and `searchUsers` respectively. +A migration in core will automatically adjust all permissions in the database to use the new naming. However, any extension code using the old name must switch to the new ones immediately to avoid security issues. To help the transfer, a warning will be thrown if the old permissions are referenced. + +We have also slightly improved tag scoping for permissions. Currently, permissions can be applied to tags if: + +- The permission is `viewForum` +- The permission is `startDiscussion` +- The permission starts with `discussion.` + +However, this doesn't work for namespaced permissions (`flarum-acme.discussion.bookmark`), or permissions that don't really have anything to do with discussions, but should still be scoped (e.g. `viewTag`). To counter this, a `tagScoped` attribute can be used on the object passed to [`registerPermission`](admin.md) to explicitly indicate whether the permission should be tag scopable. If this attribute is not provided, the current rules will be used to determine whether the permission should be tag scopable. + +## Frontend + +### Tooltip Changes + +The `flarum/common/components/Tooltip` component has been introduced as a simpler and less framework-dependent way to add tooltips. If your code is creating tooltips directly (e.g. via `$.tooltip()` in `oncreate` methods), you should wrap your components in the `Tooltip` component instead. For example: + +```tsx + + + +``` + +See [the source code](https://github.com/flarum/core/blob/master/js/src/common/components/Tooltip.tsx) for more examples and instructions. + +See [the PR](https://github.com/flarum/core/pull/2843/files) for examples of how to change existing code to use tooltips. + +### PaginatedListState + +The `flarum/common/states/PaginatedListState` state class has been introduced to abstract away most of the logic of `DiscussionListState` and `NotificationListState`. It provides support for loading and displaying paginated lists of JSON:API resources (usually models). In future releases, we will also provide an `PaginatedList` (or `InfiniteScroll`) component that can be used as a base class for these paginated lists. + +Please see [the source code](https://github.com/flarum/core/blob/master/js/src/common/states/PaginatedListState.ts) for a list of methods. + +Note that `flarum/forum/states/DiscussionListState`'s `empty` and `hasDiscussions` methods have been removed, and replaced with `isEmpty` and `hasItems` respectively. This is a breaking change. + +### New Loading Spinner + +The old `spin.js` based loading indicator has been replaced with a CSS-based solution. For the most part, no changes should be needed in extensions, but in some cases, you might need to update your spinner. This change also makes it easier to customize the spinner. + +See [this discussion](https://discuss.flarum.org/d/26994-beta16-using-the-new-loading-spinner) for more information. + +### classList util + +Ever wrote messy code trying to put together a list of classes for some component? Well, no longer! The [clsx library](https://www.npmjs.com/package/clsx) is now available as the `flarum/common/utils/classList` util. + +### User List + +An extensible user list has been added to the admin dashboard. In future releases, we hope to extract a generic model table component that can be used to list any model in the admin dashboard. + +See [the source code](https://github.com/flarum/core/blob/master/js/src/admin/components/UserListPage.tsx#L41) for a list of methods to extend, and examples of how columns should look like (can be added by extending the `columns` method and adding items to the [ItemList](frontend.md)). + +### Miscellaneous + +- Components should now call `super` for ALL Mithril lifecycle methods they define. Before, this was only needed for `oninit`, `onbeforeupdate`, and `oncreate`. Now, it is also needed in `onupdate`, `onbeforeremove`, and `onremove`. See [this GitHub issue](https://github.com/flarum/core/issues/2446) for information on why this change was made. +- The `flarum/common/utils/insertText` and `flarum/common/utils/styleSelectedText` utils have been moved to core from `flarum/markdown`. See `flarum/markdown` for an example of usage. +- The `extend` and `override` utils can now modify several methods at once by passing in an array of method names instead of a single method name string as the second argument. This is useful for extending the `oncreate` and `onupdate` methods at once. +- The `EditUserModal` component is no longer available through the `flarum/forum` namespace, it has been moved to `flarum/common`. Imports should be adjusted. +- The `Model` and `Route` JS extenders have been removed for now. There aren't currently used in any extensions that we know of. We will be reintroducing JS extenders during v1.x releases. +- The `Search` component can now be used with the `SearchState` state class. Previously, `SearchState` was missing the `getInitialSearch` method expected by the `Search` component. + +## Backend + +### Filesystem Extenders + +In this release, we refactored our use of the filesystem to more consistently use [Laravel's filesystem API](https://laravel.com/docs/8.x/filesystem). Extensions can now declare new disks, more easily use core's `flarum-assets` and `flarum-avatars` disks, and create their own storage drivers, enabling CDN and cloud storage support. + +### Compat and Closure Extenders + +In early Flarum versions, the `extend.php` file allowed arbitrary functions that allowed execution of arbitrary code one extension boot. For example: + +```php +return [ + // other extenders + function (Dispatcher $events) { + $events->subscribe(Listener\FilterDiscussionListByTags::class); + $events->subscribe(Listener\FilterPostsQueryByTag::class); + $events->subscribe(Listener\UpdateTagMetadata::class); + } +]; +``` + +This approach was difficult to maintain and provide a well-tested public API for, frequently resolved classes early (breaking all sorts of things), and was not very descriptive. With the extender API completed in beta 16, this approach is no longer necessary. Support for these closures has been removed in this stable version. + +One type of functionality for which the extender replacement isn't obvious is container bindings ([e.g. flarum/pusher](https://github.com/flarum/pusher/blob/v0.1.0-beta.14/extend.php#L33-L49)). This can be done with via the service provider extender (e.g. [a newer version of flarum/pusher](https://github.com/flarum/pusher/blob/master/extend.php#L40-L41)). + +If you are unsure about which extenders should be used to replace your use of callbacks in `extend.php`, or are not sure that such an extender exists, please comment so below or reach out! We're in the final stages of finishing up the extender API, so now is the time to comment. + +### Scheduled Commands + +The [fof/console](https://github.com/FriendsOfFlarum/console) library has been a popular way to schedule commands (e.g. for publishing scheduled posts, running DB-heavy operations, etc) for several release. In Flarum 1.0, this functionality has been brought into core's `Console` extender. See our [console extension documentation](console.md) for more information on how to create schedule commands, and our [console user documentation](../console.md) for more information on how to run scheduled commands. + +### Eager Loading Extender + +As part of solving [N+1 Query issues](https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/) in some [Flarum API endpoints](https://github.com/flarum/core/issues/2637), we have introduced a `load` method on the `ApiController` extender that allows you to indicate relations that should be eager loaded. + +This should be done if you know a relation will always be included, or will always be referenced by controller / permission logic. For example, we will always need the tags of a discussion to check what permissions a user has on that discussion, so we should eager load the discussion's `tags` relationship. For example: + +```php +return [ + // other extenders + (new Extend\ApiController(FlarumController\ListDiscussionsController::class)) + ->addInclude(['tags', 'tags.state', 'tags.parent']) + ->load('tags'), +]; +``` + +### RequestUtil + +The `Flarum\Http\RequestUtil`'s `getActor` and `withActor` should be used for getting/setting the actor (user) on requests. `$request->getAttribute('actor')` and `$request->withAttribute('actor')` are deprecated, and will be removed in v2.0. + +### Miscellaneous + +- The `Formatter` extender now has an `unparse` method that allows modifying XML before unparsing content. +- All route names must now be unique. In beta 16, uniqueness was enforced per-method; now, it is mandatory for all routes. +- API requests sent through `Flarum\Api\Client` now run through middleware, including `ThrottleApi`. This means that it is now possible to throttle login/registration calls. +- In beta 16, registering custom [searchers](search.md) was broken. It has been fixed in stable. +- The `post_likes` table in the [flarum/likes](https://github.com/flarum/likes) extension now logs the timestamp when likes were created. This isn't used in the extension, but could be used in other extensions for analytics. +- The `help` attribute of [admin settings](admin.md) no longer disappears on click. +- The `generate:migration` console command has been removed. The [Flarum CLI](https://discuss.flarum.org/d/26525-rfc-flarum-cli-alpha) should be used instead. +- The `GambitManager` util class is now considered internal API, and should not be used directly by extensions. +- The `session` attribute is no longer available on the `User` class. This caused issues with queue drivers, and was not conceptually correct (a user can have multiple sessions). The current session is still available via the `$request` instance. +- The `app`, `base_path`, `public_path`, `storage_path`, and `event` global helpers have been restored, but deprecated perpetually. These exist in case Laravel packages need them; they **should not** be used directly by Flarum extension code. The `flarum/laravel-helpers` package has been abandoned. +- The following deprecated features from beta 16 have been removed: + - The `TextEditor`, `TextEditorButton`, and `SuperTextarea` components are no longer exported through the `flarum/forum` namespace, but through `flarum/common` (with the exception of `SuperTextarea`, which has been replaced with `flarum/common/utils/BasicEditorDriver`). + - Support for `Symfony\Component\Translation\TranslatorInterface` has been removed, `Symfony\Contracts\Translation\TranslatorInterface` should be used instead. + - All backwards compatibility layers for the [beta 16 access token refactors](update-b16.md#access-token-and-authentication-changes) have been removed + - The `GetModelIsPrivate` event has been removed. The `ModelPrivate` extender should be used instead. + - The `Searching` (for both `User` and `Discussion` models), `ConfigureAbstractGambits`, `ConfigureDiscussionGambits`, and `ConfigureUserGambits` events have been removed. The `SimpleFlarumSearch` extender should be used instead. + - The `ConfigurePostsQuery` event has been removed. The `Filter` extender should be used instead. + - The `ApiSerializer` extender's `mutate` method has been removed. The same class's `attributes` method should be used instead. + - The `SearchCriteria` and `SearchResults` util classes have been removed. `Flarum\Query\QueryCriteria` and `Flarum\Query\QueryResults` should be used instead. + - The `pattern` property of `AbstractRegexGambit` has been removed; the `getGambitPattern` method is now a required abstract method. + - The `AbstractSearch` util class has been removed. `Flarum\Search\SearchState` and `Flarum\Filter\FilterState` should be used instead. + - The `CheckingPassword` event has been removed, the `Auth` extender should be used instead. + +## Tags Extension Changes + +As mentioned above, [tag scopable permissions](#permissions-changes) can now be explicitly declared. + +We've also made several big refactors to significantly improve tags performance. + +Firstly, the [Tag](https://github.com/flarum/tags/blob/d093ca777ba81f826157522c96680717d3a90e24/src/Tag.php#L38-L38) model's static `getIdsWhereCan` and `getIdsWhereCannot` methods have been removed. These methods scaled horribly on forums with many tags, sometimes adding several seconds to response time. + +These methods have been replaced with a `whereHasPermission` [Eloquent dynamic scope](https://laravel.com/docs/8.x/eloquent#dynamic-scopes) that returns a query. For example: + +`Tag::whereHasPermission($actor, 'viewDiscussions)`. + +That query can then be used in other DB queries, or further constricted to retrieve individual tags. + +Secondly, we no longer load in all tags as part of the initial payload. The initial payload contains all top-level primary tags, and the top 3 secondary tags. Other tags are loaded in as needed. Future releases will paginate secondary tags. This should enable forums to have thousands of secondary tags without significant performance impacts. These changes mean that extensions should not assume that all tags are available in the model store. + +## Testing Library Changes + +- Bundled extensions will not be automatically enabled; all enabled extensions must be specified in that test case. +- `setting` and `config` methods have been added that allow configuring settings and config.php values before the tested application boots. See [the testing docs](testing.md) for more information. +- The `php flarum test:setup` command will now drop the existing test DB tables before creating the database. This means that you can run `php flarum test:setup` to ensure a clean database without needing to go into the database and drop tables manually. diff --git a/versioned_docs/version-1.x/extend/update-1_x.md b/versioned_docs/version-1.x/extend/update-1_x.md new file mode 100644 index 000000000..c33134f19 --- /dev/null +++ b/versioned_docs/version-1.x/extend/update-1_x.md @@ -0,0 +1,139 @@ +# Updating For 1.x + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## 1.7 + +### Frontend + +- Frontend extenders similar to the backend have been added, we highly recommend using them instead of the old method (https://docs.flarum.org/extend/models#adding-new-models-1), (https://docs.flarum.org/extend/routes#frontend-routes). +- There is a new tag selection component (https://github.com/flarum/framework/blob/360a2ba1d886df3fc6d326be932c5431ee9df8cf/extensions/tags/js/src/common/components/TagSelectionModal.tsx). + +### Backend + +- Support for php 8.2, deprecations are still thrown by some packages, the testing workflow has been updated to ignore deprecations on 8.2 +- The `/api` endpoint now contains the actor as an included relationship. +- The `Model::dateAttribute($attribute)` extender is deprecated, use `Model::cast($attribute, 'datetime')` instead. + +### Tooling + +- New `phpstan` package to run static code analysis on your extensions for code safety (https://docs.flarum.org/extend/static-code-analysis). +- New `jest-config` package to run frontend unit and component tests (https://docs.flarum.org/extend/testing). + +## 1.6 Changes + +### Backend + +- Added customizable session drivers through the `Session` extender. + +## 1.5 Changes + +### Frontend + +- More portions of the frontend are now written in TypeScript, providing a better extension development experience. +- Modals can be used in stacks, allowing for multiple modals to be open at once. This is useful for modals that open other modals: `app.modal.show(ModalComponent, { attrs }, true)`. + +### Backend + +- There is a new `createTableIfNotExists` migration helper, which can be used to create tables only if they don't already exist. + +## 1.4 Changes + +No developer-facing changes were made in Flarum v1.4. + +## 1.3 Changes + +Flarum v1.3 included mostly QoL improvements. Below are listed note worthy changes for extension developers: + +### Frontend + +- More portions of the frontend are now written in TypeScript, providing a better extension development experience. +- Frontend errors will no longer cause the forum to crash into a NoJs page. The extension will fail to execute its frontend code (initializer) and display an error to the admin through an alert, and to all users through the console. The frontend will continue to execute without the extension's frontend changes. +- The markdown toolbar can now be used on the admin side. + +### Backend + +- Calculation of the `number` attribute on `posts` has changed and no longer relies on the discussion model's `post_number_index` attribute which is now deprecated and will be removed in 2.0 +- Extension event listeners are now added after core even listeners, this should generally cause no changes in behavior. + +### Tooling + +- The backend tests workflow now automatically fails tests if there are any PHP warnings and notices. + +## 1.2 Changes + +Flarum v1.2 included quite a few bugfixes, internal refactors, and new features. The following recaps the most important changes for extension developers: + +### Frontend + +- Flarum core now passes TypeScript type checking (on the portion written in TypeScript). Additionally, major portions of the frontend (models, the application instance, and others) are now written in TypeScript. These changes should make it much easier and more fruitful to write extensions in TypeScript. +- Instead of directly using Less variables in CSS code, core now uses CSS variables. For the most part, we've just created CSS variables and set their values to the Less variables. This should make theming and customizing CSS a lot easier. https://github.com/flarum/core/pull/3146. +- Dropdowns can now be lazy-drawn to improve performance. You can do this by setting the lazy draw attr to "true". https://github.com/flarum/core/pull/2925. +- [Textarea-type settings](https://github.com/flarum/core/pull/3141) are now supported through the `app.extensionData.registerSetting` util. +- You can now use Webpack 5 to bundle your extension's code. This will offer minor bundle size improvements. +- A new `flarum/common/components/ColorPreviewInput` component [has been added](https://github.com/flarum/core/pull/3140). It can be used directly, or through the `color-preview` type when registered via `app.extensionData.registerSetting`. +- Extensions can now [modify the minimum search length](https://github.com/flarum/core/pull/3130) of the `Search` component. +- The following components are now extensible: + - The "colors" part of the Appearance page in the admin dashboard: https://github.com/flarum/core/pull/3186 + - The `StatusWidget` dropdown in the admin dashboard: https://github.com/flarum/core/pull/3189 + - `primaryControls` in the notification list: https://github.com/flarum/core/pull/3204 +- Extensions now have finer control over positioning when adding elements to the DiscussionPage sidebar items: https://github.com/flarum/core/pull/3165 +- + +### Backend + +- An [extender for settings defaults](https://github.com/flarum/core/pull/3127) has been added. This should be used instead of the `addSettings` migration helper, which has been deprecated. +- You can now [generate Less variables from setting values](https://github.com/flarum/core/pull/3011) via the `Settings` extender. +- Extensions can now [override/supplement blade template namespaces](https://github.com/flarum/core/pull/3167) through the `View` extender, meaning custom blade templates can be used instead of the default ones added by core or extensions. +- You can now define [custom Less functions through PHP](https://github.com/flarum/core/pull/3190), allowing you to use some backend logic in your Less theming. +- Extensions can now create [custom page title drivers](https://github.com/flarum/core/pull/3109/files) for titles in server-returned HTML. +- Custom logic can now be used when [deciding which relations to eager-load](https://github.com/flarum/core/pull/3116). +- Events [are now dispatched](https://github.com/flarum/core/pull/3203) for the `Notification\Read` and `Notification\ReadAll` events. +- An `ImageManager` instance is now [bound into the container](https://github.com/flarum/core/pull/3195), and can be configured to use either the `gd` or `imagick` backing drivers via the `"intervention.driver"` key in `config.php`. +- User IP addresses are now passed to the [API Client](https://github.com/flarum/core/pull/3124). +- A custom revision versioner implentation [can be set via container bindings](https://github.com/flarum/core/pull/3183) to customize how asset versions are named. +- A SlugManager instance [is now available](https://github.com/flarum/core/pull/3194) in blade templates via the `slugManager` variable. + +### Misc + +- Translations now support the `zero`, `one`, `two`, `few`, and `many` localized plural rules for `plural` ICU MessageFormat translations. This was done through the [`Intl.PluralRules` helper](https://github.com/flarum/core/issues/3072). +- Translations are now used for page titles, so that the format can be customized via language packs or [Linguist](https://discuss.flarum.org/d/7026-linguist-customize-translations-with-ease): https://github.com/flarum/core/pull/3077, https://github.com/flarum/core/pull/3228 +- API endpoints for retrieving single groups, as well as support for filtering groups on the plural get endpoint, [have been added](https://github.com/flarum/core/pull/3084). + + +### Tooling + + +- The `flarum-cli infra` command can now be used to update or enable various infrastructure features. You can now add the following to your extension in just one command: + - TypeScript + - Prettier for JS/TS formatting + - Backend testing with PHPUnit + - Code formatting with StyleCI + - EditorConfig support + - GitHub actions for automating testing, linting, type checking, and building. +- You can also exclude any files from these updates by adding their relative path to the "extra.flarum-cli" key's array in your extension's `composer.json` file. For example, if you wanted to exclude your tsconfig file from any updates by the infra system, the "extra.flarum-cli" key's value should be `["js/tsconfig.json"]`. +- The `flarum-cli audit infra` can be used to check that all infra modules your extension uses are up to date. The `--fix` flag can be used to automatically fix any issues, which has essentially the same effect as running `flarum-cli infra` for each outdated module. +- All `flarum-cli` commands can now be run with a `--no-interaction` flag to prevent prompts. Defaults will be used when possible, and errors will be thrown if a prompt is needed and there is no default. +- Frontend GH actions now support type-checking, as well as type coverage reports. + +## 1.1 Changes + +Flarum version 1.1 mostly focuses on bugfixes and quality-of-life improvements following our stable release earlier this year. These are mainly user-facing and internal infrastructure changes, so extensions are not significantly affected. + +### Frontend + +- Flarum now has an organization-wide prettier config package under [`@flarum/prettier-config`](https://github.com/flarum/prettier-config). +- Most custom (setting or data based) coloring in core is now done via [CSS custom properties](https://github.com/flarum/core/pull/3001). +- Typehinting for Flarum's globals are now [supported in extensions](https://github.com/flarum/core/pull/2992). +- You can now pass extra attrs to the `Select` component, and they will be [passed through to the DOM](https://github.com/flarum/core/pull/2959). +- The `DiscussionPage` component is now organized [as an item list](https://github.com/flarum/core/pull/3004), so it's easier for extensions to change its content. +- Extensions [can now edit](https://github.com/flarum/core/pull/2935) the `page` parameter of `PaginatedListState`. + +### Backend + +- Flarum now comes with a [Preload extender](https://github.com/flarum/core/pull/3057) for preloading any custom frontend assets. +- A new [Theme](https://github.com/flarum/core/pull/3008) extender now allows overriding Less files and internal imports. This allows themes to more easily completely replace Less modules. diff --git a/versioned_docs/version-1.x/extend/update-b10.md b/versioned_docs/version-1.x/extend/update-b10.md new file mode 100644 index 000000000..aaa98a2a5 --- /dev/null +++ b/versioned_docs/version-1.x/extend/update-b10.md @@ -0,0 +1,53 @@ +# Updating For Beta 10 + +Beta 10 further solidifies the core architecture, offering new extenders as a stable, use-case-driven API for extending Flarum's core. A few small changes may necessitate updates to your extensions to make them compatible with Beta 10. These are detailed below. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Breaking Changes + +- The `Flarum\Event\GetDisplayName` class has been moved to `Flarum\User\Event\GetDisplayName`. +- The `Flarum\Http\Exception\ForbiddenException` has been removed. Use `Flarum\User\Exception\PermissionDeniedException` instead. +- The `assertGuest()` method of the `Flarum\User\AssertPermissionTrait` has been removed without replacement. +- Old error handling middleware and exception handler classes were removed (see "New Features" for more details): + - `Flarum\Api\Middleware\HandleErrors` + - `Flarum\Http\Middleware\HandleErrorsWithView` + - `Flarum\Http\Middleware\HandleErrorsWithWhoops` + - `Flarum\Api\ErrorHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + - `Flarum\Api\ExceptionHandler\FloodingExceptionHandler` + - `Flarum\Api\ExceptionHandler\IlluminateValidationExceptionHandler` + - `Flarum\Api\ExceptionHandler\InvalidAccessTokenExceptionHandler` + - `Flarum\Api\ExceptionHandler\InvalidConfirmationTokenExceptionHandler` + - `Flarum\Api\ExceptionHandler\MethodNotAllowedExceptionHandler` + - `Flarum\Api\ExceptionHandler\ModelNotFoundExceptionHandler` + - `Flarum\Api\ExceptionHandler\PermissionDeniedExceptionHandler` + - `Flarum\Api\ExceptionHandler\RouteNotFoundExceptionHandler` + - `Flarum\Api\ExceptionHandler\TokenMismatchExceptionHandler` + - `Flarum\Api\ExceptionHandler\ValidationExceptionHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + - `Flarum\Api\ExceptionHandler\FallbackExceptionHandler` + +## Recommendations + +- We tweaked the [recommended flarum/core version constraints for extensions](start.md#composer-json). We now recommend you mark your extension as compatible with the current and the upcoming beta release. (For beta.10, that would be any beta.10.x and beta.11.x version.) The core team will strive to make this work well by deprecating features before removing them. More details on this change in [this pull request](https://github.com/flarum/docs/pull/75). + +## New Features + +- New, extensible **error handling** stack in the `Flarum\Foundation\ErrorHandling` namespace: The `Registry` maps exceptions to "types" and HTTP status codes, `HttpFormatter` instances turn them into HTTP responses. Finally, `Reporter` instances are notified about unknown exceptions. + - You can build custom exception classes that will abort the current request (or console command). If they have semantic meaning to your application, they should implement the `Flarum\Foundation\KnownError` interface, which exposes a "type" that is used to render pretty error pages or dedicated error messages. + - More consistent use of HTTP 401 and 403 status codes. HTTP 401 should be used when logging in (i.e. authenticating) could make a difference; HTTP 403 is reserved for requests that fail because the already authenticated user is lacking permissions to do something. + - The `assertRegistered()` and `assertPermission()` methods of the `Flarum\User\AssertPermissionTrait` trait have been changed to match above semantics. See [this pull request](https://github.com/flarum/core/pull/1854) for more details. + - Error views are now determined based on error "type", not on status code (see [bdac88b](https://github.com/flarum/core/commit/bdac88b5733643b9c5dabae9e09a64d9f6e41d58)) +- **Queue support**: This release incorporates Laravel's illuminate/queue package, which allows offloading long-running tasks (such as email sending or regular cleanup jobs) onto a dedicated worker process. These changes are mostly under the hood, the next release(s) will start using the queue system for sending emails. By default, Flarum will use the "sync" queue driver, which executes queued tasks immediately. This is far from ideal and mostly guarantees a hassle-free setups. Production-grade Flarum installs are expected to upgrade to a more full-featured queue adapter. +- The `Flarum\Extend\LanguagePack` now accepts an optional path in its constructor. That way, language packs can store their locales in a different directory if they want to. +- The `formatContent()` method of `Flarum\Post\CommentPost` can now be called without an HTTP request instance, e.g. when rendering a post in an email template. + +## Deprecations + +- **Reminder**: In previous versions of Flarum, an extensions' main file was named `bootstrap.php`. This name will no longer be supported in the stable 0.1 release. Make sure your extension uses the name `extend.php`. +- Laravel's global string and array helpers (e.g. `str_contains()` and `array_only()`) are deprecated in favor of their class based alternatives (`Illuminate\Support\Str::contains()` and `Illuminate\Support\Arr::only()`). See the [announcement](https://laravel-news.com/laravel-5-8-deprecates-string-and-array-helpers) and [pull request](https://github.com/laravel/framework/pull/26898) for more information. diff --git a/versioned_docs/version-1.x/extend/update-b12.md b/versioned_docs/version-1.x/extend/update-b12.md new file mode 100644 index 000000000..81cb3eee0 --- /dev/null +++ b/versioned_docs/version-1.x/extend/update-b12.md @@ -0,0 +1,35 @@ +# Updating For Beta 12 + +Beta 12 packs several new features for extension developers, but also continues our cleanup efforts which results in a few changes, so please read this guide carefully to find out whether + your extensions are affected. We invested extra effort to introduce new functionality in a backward-compatible manner or first deprecate functionality before it will be removed in the next release, in line with our [versioning recommendations](start.md#composer-json). + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Deprecations / Upcoming breaking changes + +- **Reminder**: In previous versions of Flarum, an extensions' main file was named `bootstrap.php`. This name will no longer be supported in the stable 0.1 release. Make sure your extension uses the name `extend.php`. +- PHP 7.1 support will be dropped in beta.13. +- Using library classes from the `Zend` namespace is now deprecated and will be removed in beta.13. Use the `Laminas` namespace instead. See [PR #1963](https://github.com/flarum/core/pull/1963). +- The `Flarum\Util\Str::slug()` method has been deprecated. Use `Illuminate\Support\Str::slug()` instead. +- The `Flarum\Event\ConfigureMiddleware` has been deprecated. We finally have a [proper replacement](middleware.md) - see "New Features" below. Therefore, it will be removed in beta.13. +- If you implement the `Flarum\Mail\DriverInterface`: + - Returning a plain array of field names from the `availableSettings()` method is deprecated, but still supported. It must now return an array of field names mapping to their type. See [the inline documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L25-L32) for more details. + - Implement the `validate()` method that will be required in beta.13. See [its documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L34-L48). + - Implement the `canSend()` method that will be required in beta.13. See [its documentation](https://github.com/flarum/core/blob/08e40bc693cce7be02d4fb24633553c7eaf2738d/src/Mail/DriverInterface.php#L50-L54). + +## New Features + +- New **PHP extenders**: + - `Flarum\Extend\Middleware` offers methods for adding, removing or replacing middleware in our three middleware stacks (api, forum, admin). We also added [documentation](middleware.md) for this feature. + - `Flarum\Extend\ErrorHandling` lets you configure status codes and other aspects of our error handling stack depending on error types or exception classes. +- **JavaScript**: + - The `flarum/components/Select` component now supports a `disabled` prop. See [PR #1978](https://github.com/flarum/core/pull/1978). + +## Other changes / Recommendations + +- The `TextFormatter` library has been updated to (at least) version 2.3.6. If you are using it (likely through our own `Flarum\Formatter\Formatter` class), we recommend scanning [the library's changelog](https://github.com/s9e/TextFormatter/blob/2.3.6/CHANGELOG.md). +- The JS `slug()` helper from the `flarum/utils/string` module should only be used to *suggest* slugs to users, not enforce them. It does not employ any sophisticated transliteration logic like its PHP counterpart. diff --git a/versioned_docs/version-1.x/extend/update-b13.md b/versioned_docs/version-1.x/extend/update-b13.md new file mode 100644 index 000000000..1b19a9714 --- /dev/null +++ b/versioned_docs/version-1.x/extend/update-b13.md @@ -0,0 +1,40 @@ +# Updating For Beta 13 + +Beta 13 ships with several new extenders to simplify building and maintaining extensions. We do our best to create backward compatibility changes. We recommend changing to new Extenders as soon as they are available. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Breaking Changes + +- Dropped support for PHP 7.1. +- Classes from the `Zend` namespace are now removed. Use the `Laminas` namespace instead. See [PR #1963](https://github.com/flarum/core/pull/1963). +- The `Flarum\Util\Str::slug()` method has been removed including the class. Use `Illuminate\Support\Str::slug()` instead. +- The `Flarum\Event\ConfigureMiddleware` has been removed. Use the [proper replacement](middleware.md). +- Several events used in Event Listeners have been removed, use their [replacement extender](start.md#extenders) instead. +- The LanguagePack extender only loads keys from extensions that are enabled. The translations loaded are based on the yaml files matching the [i18n namespace](i18n.md#appendix-a-standard-key-format). +- All notifications are now sent through the queue; without a queue driver they will run as usual. +- The implementation of avatar upload changed, we're [no longer storing files temporarily on disk](https://github.com/flarum/core/pull/2117). +- The SES mail driver [has been removed](https://github.com/flarum/core/pull/2011). +- Mail driver backward compatibility from beta 12 has been removed, use the new Mail extender or implement the [modified interface](https://github.com/flarum/core/blob/master/src/Mail/DriverInterface.php). + +## Recommendations + +- Beta 14 will ship with a rewrite in the frontend (javascript). If you're building for that release, make sure to follow our [progress](https://github.com/flarum/core/pull/2126). + +## New Features + +- A ton of new extenders: + - [Middleware extender](https://github.com/flarum/core/pull/2017) + - [Console extender](https://github.com/flarum/core/pull/2057) + - [CSRF extender](https://github.com/flarum/core/pull/2095) + - [Event extender](https://github.com/flarum/core/pull/2097) + - [Mail extender](https://github.com/flarum/core/pull/2012) + - [Model extender](https://github.com/flarum/core/pull/2100) + +## Deprecations + +- Several events [have been marked deprecated](https://github.com/flarum/core/commit/4efdd2a4f2458c8703aae654f95c6958e3f7b60b) to be removed in beta 14. diff --git a/versioned_docs/version-1.x/extend/update-b14.md b/versioned_docs/version-1.x/extend/update-b14.md new file mode 100644 index 000000000..fb95b24fe --- /dev/null +++ b/versioned_docs/version-1.x/extend/update-b14.md @@ -0,0 +1,777 @@ +# Updating For Beta 14 + +This release brings a large chunk of breaking changes - hopefully the last chunk of this size before our stable release. +In order to prepare the codebase for the upcoming stable release, we decided it was time to modernize / upgrade / exchange some of the underlying JavaScript libraries that are used in the frontend. +Due to the nature and size of these upgrades, we have to pass on some of the breaking changes to you, our extension developers. + +On the bright side, this overdue upgrade brings us closer to the conventions of best practices of [Mithril.js](https://mithril.js.org/), the mini-framework used for Flarum's UI. +Mithril's 2.0 release sports a more consistent component interface, which should be a solid foundation for years to come. +Where possible, we replicated old APIs, to ease the upgrade and give you time to do the full transition. +Quite a few breaking changes remain, though - read more below. + +:::tip + +If you need help with the upgrade, our friendly community will gladly help you out either [on the forum](https://discuss.flarum.org/t/extensibility) or [in chat](https://flarum.org/chat/). + +::: + +To ease the process, we've clearly separated the changes to the [frontend (JS)](#frontend-javascript) from those in the [backend (PHP)](#backend-php) below. +If your extension does not change the UI, consider yourself lucky. :-) + +A [summary of the frontend changes](#required-frontend-changes-recap) is available towards the end of this guide. + +## Frontend (JavaScript) + +### Mithril 2.0: Concepts + +Most breaking changes required by beta 14 are prompted by changes in Mithril 2. +[Mithril's upgrade guide](https://mithril.js.org/migration-v02x.html) is an extremely useful resource, and should be consulted for more detailed information. A few key changes are explained below: + +#### props -> attrs; initProps -> initAttrs + +Props passed into component are now referred to as `attrs`, and can be accessed via `this.attrs` where you would prior use `this.props`. This was done to be closer to Mithril's preferred terminology. We have provided a temporary backwards compatibility layer for `this.props`, but recommend using `this.attrs`. + +Accordingly, `initProps` has been replaced with `initAttrs`, with a similar BC layer. + +#### m.prop -> `flarum/utils/Stream` + +Mithril streams, which were available via `m.prop` in Mithril 0.2, are now available via `flarum/utils/Stream`. `m.prop` will still work for now due to a temporary BC layer. + +#### m.withAttr -> withAttr + +The `m.withAttr` util has been removed from Mithril. We have provided `flarum/utils/withAttr`, which does the same thing. A temporary BC layer has been added for `m.withAttr`. + +#### Lifecycle Hooks + +In mithril 0.2, we had 2 "lifecycle hooks": + +`init`, an unofficial hook which ran when the component instance was initialized. + +`config`, which ran when components were created, and on every redraw. + + +Mithril 2 has the following hooks; each of which take `vnode` as an argument: + +- `oninit` +- `oncreate` +- `onbeforeupdate` +- `onupdate` +- `onbeforeremove` +- `onremove` + +Please note that if your component is extending Flarum's helper `Component` class, you must call `super.METHOD(vnode)` if using `oninit`, `oncreate`, and `onbeforeupdate`. + +More information about what each of these do can be found [in Mithril's documentation](https://mithril.js.org/lifecycle-methods.html). + +A trivial example of how the old methods map to the new is: + +```js +class OldMithrilComponent extends Component { + init() { + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + config(element, isInitialized) { + console.log('Code to run on every redraw AND when the element is first attached'); + + if (isInitialized) return; + + console.log('Code to execute only once when components are first created and attached to the DOM'); + + context.onunload = () => { + console.log('Code to run when the component is removed from the DOM'); + } + } + + view() { + // In mithril 0, you could skip redrawing a component (or part of a component) by returning a subtree retain directive. + // See https://mithril.js.org/archive/v0.2.5/mithril.render.html#subtree-directives + // dontRedraw is a substitute for logic; usually, this is used together with SubtreeRetainer. + if (dontRedraw()) return { subtree: 'retain' }; + + return

Hello World!

; + } +} + +class NewMithrilComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + console.log('Code to run when component instance created, but before attached to the DOM.'); + } + + oncreate(vnode) { + super.oncreate(vnode); + + console.log('Code to run when components are first created and attached to the DOM'); + } + + onbeforeupdate(vnode, oldVnode) { + super.onbeforeupdate(vnode); + + console.log('Code to run BEFORE diffing / redrawing components on every redraw'); + + // In mithril 2, if we want to skip diffing / redrawing a component, we return "false" in its onbeforeupdate lifecycle hook. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeupdate + // This is also typically used with SubtreeRetainer. + if (dontRedraw()) return false; + } + + onupdate(vnode) { + // Unlike config, this does NOT run when components are first attached. + // Some code might need to be replicated between oncreate and onupdate. + console.log('Code to run on every redraw AFTER the DOM is updated.'); + } + + onbeforeremove(vnode) { + // This is run before components are removed from the DOM. + // If a promise is returned, the DOM element will only be removed when the + // promise completes. It is only called on the top-level component that has + // been removed. It has no equivalent in Mithril 0.2. + // See https://mithril.js.org/lifecycle-methods.html#onbeforeremove + return Promise.resolve(); + } + + onremove(vnode) { + console.log('Code to run when the component is removed from the DOM'); + } +} +``` + +#### Children vs Text Nodes + +In Mithril 0.2, every child of a vnode is another vnode, stored in `vnode.children`. For Mithril 2, as a performance optimization, vnodes with a single text child now store that text directly in `vnode.text`. For developers, that means that `vnode.children` might not always contain the results needed. Luckily, text being stored in `vnode.text` vs `vnode.children` will be the same each time for a given component, but developers should be aware that at times, they might need to use `vnode.text` and not `vnode.children`. + +Please see [the mithril documentation](https://mithril.js.org/vnodes.html#structure) for more information on vnode structure. + +#### Routing API + +Mithril 2 introduces a few changes in the routing API. Most of these are quite simple: + +- `m.route()` to get the current route has been replaced by `m.route.get()` +- `m.route(NEW_ROUTE)` to set a new route has been replaced by `m.route.set(NEW_ROUTE)` +- When registering new routes, a component class should be provided, not a component instance. + +For example: + +```js +// Mithril 0.2 +app.routes.new_page = { path: '/new', component: NewPage.component() } + +// Mithril 2.0 +app.routes.new_page = { path: '/new', component: NewPage } +``` + +Additionally, the preferred way of defining an internal (doesn't refresh the page when clicked) link has been changed. The `Link` component should be used instead. + +```js +// Mithril 0.2 +
Link Content + +// Mithril 2 +import Link from 'flarum/components/Link'; + +Link Content +``` + +You can also use `Link` to define external links, which will just render as plain `Children` html links. + +For a full list of routing-related changes, please see [the mithril documentation](https://mithril.js.org/migration-v02x.html). + +#### Redraw API + +Mithril 2 introduces a few changes in the redraw API. Most of these are quite simple: + +- Instead of `m.redraw(true)` for synchronous redraws, use `m.redraw.sync()` +- Instead of `m.lazyRedraw()`, use `m.redraw()` + +Remember that Mithril automatically triggers a redraw after DOM event handlers. The API for preventing a redraw has also changed: + +```js +// Mithril 0.2 + + +// Mithril 2 + +``` + +#### AJAX + +The `data` parameter of `m.request({...})` has been split up into `body` and `params`. + +For examples and other AJAX changes, see [the mithril documentation](https://mithril.js.org/migration-v02x.html#mrequest). + +#### Promises + +`m.deferred` has been removed, native promises should be used instead. For instance: + +```js +// Mithril 0.2 +const deferred = m.deferred(); + +app.store.find('posts').then(result => deferred.resolve(result)); + +return deferred.promise; + +// Mithril 2 +return app.store.find('posts'); +``` + +#### Component instances should not be stored + +Due to optimizations in Mithril's redrawing algorithms, [component instances should not be stored](https://mithril.js.org/components.html#define-components-statically,-call-them-dynamically). + +So whereas before, you might have done something like: + +```js +class ChildComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return

{this.counter}

; + } +} +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.child = new ChildComponent(); + } + + view() { + return ( +
+ + {this.child.render()} +
+ ) + } +} +``` + +That will no longer work. In fact; the Component class no longer has a render method. + +Instead, any data needed by a child component that is modified by a parent component should be passed in as an attr. For instance: + +```js +class ChildComponent extends Component { + view() { + return

{this.attrs.counter}

; + } +} + +class ParentComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + this.counter = 0; + } + + view() { + return ( +
+ + +
+ ) + } +} +``` + +For more complex components, this might require some reorganization of code. For instance, let's say you have data that can be modified by several unrelated components. +In this case, it might be preferable to create a POJO "state instance' for this data. These states are similar to "service" singletons used in Angular and Ember. For instance: + +```js +class Counter { + constructor() { + this._counter = 0; + } + + increaseCounter() { + this._counter += 1; + } + + getCount() { + return this._counter; + } +} + +app.counter = new Counter(); + +extend(HeaderSecondary.prototype, 'items', function(items) { + items.add('counterDisplay', +
+

Counter: {app.counter.getCount()}

+
+ ); +}) + +extend(HeaderPrimary.prototype, 'items', function(items) { + items.add('counterButton', +
+ +
+ ); +}) +``` + +This "state pattern" can be found throughout core. Some non-trivial examples are: + +- PageState +- SearchState and GlobalSearchState +- NotificationListState +- DiscussionListState + +### Changes in Core + +#### Modals + +Previously, modals could be opened by providing a `Modal` component instance: + +```js +app.modal.show(new LoginModal(identification: 'prefilledUsername')); +``` + +Since we don't store component instances anymore, we pass in the component class and any attrs separately. + +```js +app.modal.show(LoginModal, {identification: 'prefilledUsername'}); +``` + +The `show` and `close` methods are still available through `app.modal`, but `app.modal` now points to an instance of `ModalManagerState`, not of the `ModalManager` component. +Any modifications by extensions should accordingly be done to `ModalManagerState`. + +#### Alerts + +Previously, alerts could be opened by providing an `Alert` component instance: + +```js +app.alerts.show(new Alert(type: 'success', children: 'Hello, this is a success alert!')); +``` + +Since we don't store component instances anymore, we pass in a component class, attrs, children separately. The `show` method has 3 overloads: + +```js +app.alerts.show('Hello, this is a success alert!'); +app.alerts.show({type: 'success'}, 'Hello, this is a success alert!'); +app.alerts.show(Alert, {type: 'success'}, 'Hello, this is a success alert!'); +``` + +Additionally, the `show` method now returns a unique key, which can then be passed into the `dismiss` method to dismiss that particular alert. +This replaces the old method of passing the alert instance itself to `dismiss`. + +The `show`, `dismiss`, and `clear` methods are still available through `app.alerts`, but `app.alerts` now points to an instance of `AlertManagerState`, not of the `AlertManager` component. +Any modifications by extensions should accordingly be done to `AlertManagerState`. + +#### Composer + +Since we don't store a component instances anymore, a number of util methods from `Composer`, `ComposerBody` (and it's subclasses), and `TextEditor` have been moved onto `ComposerState`. + +For `forum/components/Composer`, `isFullScreen`, `load`, `clear`, `show`, `hide`, `close`, `minimize`, `fullScreen`, and `exitFullScreen` have been moved to `forum/states/ComposerState`. They all remain accessible via `app.composer.METHOD` + +A `bodyMatches` method has been added to `forum/states/ComposerState`, letting you check whether a certain subclass of `ComposerBody` is currently open. + +Various input fields are now stored as [Mithril Streams](https://mithril.js.org/stream.html) in `app.composer.fields`. For instance, to get the current composer content, you could use `app.composer.fields.content()`. Previously, it was available on `app.composer.component.content()`. **This is a convention that `ComposerBody` subclasses that add inputs should follow.** + +`app.composer.component` is no longer available. + +- Instead of `app.composer.component instanceof X`, use `app.composer.bodyMatches(X)`. +- Instead of `app.composer.component.props`, use `app.composer.body.attrs`. +- Instead of `app.composer.component.editor`, use `app.composer.editor`. + +For `forum/components/TextEditor`, the `setValue`, `moveCursorTo`, `getSelectionRange`, `insertAtCursor`, `insertAt`, `insertBetween`, `replaceBeforeCursor`, `insertBetween` methods have been moved to `forum/components/SuperTextarea`. + +Also for `forum/components/TextEditor`, `this.disabled` is no longer used; `disabled` is passed in as an attr instead. It may be accessed externally via `app.composer.body.attrs.disabled`. + +Similarly to Modals and Alerts, `app.composer.load` no longer accepts a component instance. Instead, pass in the body class and any attrs. For instance, + +```js +// Mithril 0.2 +app.composer.load(new DiscussionComposer({user: app.session.user})); + +// Mithril 2 +app.composer.load(DiscussionComposer, {user: app.session.user}) +``` + +Finally, functionality for confirming before unloading a page with an active composer has been moved into the `common/components/ConfirmDocumentUnload` component. + +#### Widget and DashboardWidget + +The redundant `admin/components/Widget` component has been removed. `admin/components/DashboardWidget` should be used instead. + +#### NotificationList + +For `forum/components/NotificationList`, the `clear`, `load`, `loadMore`, `parseResults`, and `markAllAsRead` methods have been moved to `forum/states/NotificationListState`. + +Methods for `isLoading` and `hasMoreResults` have been added to `forum/states/NotificationListState`. + +`app.cache.notifications` is no longer available; `app.notifications` (which points to an instance of `NotificationListState`) should be used instead. + +#### Checkbox + +Loading state in the `common/components/Checkbox` component is no longer managed through `this.loading`; it is now passed in as a prop (`this.attrs.loading`). + +#### Preference Saver + +The `preferenceSaver` method of `forum/components/SettingsPage` has been removed without replacement. This is done to avoid saving component instances. Instead, preferences should be directly saved. For instance: + +```js +// Old way +Switch.component({ + children: app.translator.trans('core.forum.settings.privacy_disclose_online_label'), + state: this.user.preferences().discloseOnline, + onchange: (value, component) => { + this.user.pushAttributes({ lastSeenAt: null }); + this.preferenceSaver('discloseOnline')(value, component); + }, +}) + +// Without preferenceSaver +Switch.component({ + children: app.translator.trans('core.forum.settings.privacy_disclose_online_label'), + state: this.user.preferences().discloseOnline, + onchange: (value) => { + this.discloseOnlineLoading = true; + + this.user.savePreferences({ discloseOnline: value }).then(() => { + this.discloseOnlineLoading = false; + m.redraw(); + }); + }, + loading: this.discloseOnlineLoading, +}) +``` + +A replacement will eventually be introduced. + +#### DiscussionListState + +For `forum/components/DiscussionList`, the `requestParams`, `sortMap`, `refresh`, `loadResults`, `loadMore`, `parseResults`, `removeDiscussion`, and `addDiscussion` methods have been moved to `forum/states/DiscussionListState`. + +Methods for `hasDiscussions`, `isLoading`, `isSearchResults`, and `empty` have been added to `forum/states/DiscussionListState`. + +`app.cache.discussions` is no longer available; `app.discussions` (which points to an instance of `DiscussionListState`) should be used instead. + +#### PageState + +`app.current` and `app.previous` no longer represent component instances, they are now instances of the `common/states/PageState` class. This means that: + +- Instead of `app.current instanceof X`, use `app.current.matches(X)` +- Instead of `app.current.PROPERTY`, use `app.current.get('PROPERTY')`. Please note that all properties must be exposed EXPLICITLY via `app.current.set('PROPERTY', VALUE)`. + +#### PostStream + +Logic from `forum/components/PostStreamScrubber`'s `update` method has been moved to `forum/components/PostStream`'s `updateScrubber` method. + +For `forum/components/PostStream`, the `update`, `goToFirst`, `goToLast`, `goToNumber`, `goToIndex`, `loadNearNumber`, `loadNearIndex`, `loadNext`, `loadPrevious`, `loadPage`, `loadRange`, `show`, `posts`, `reset`, `count`, and `sanitizeIndex` methods have been moved to `forum/states/PostStreamState`. + +Methods for `disabled` and `viewingEnd` have been added to `forum/states/PostStreamState`. + +#### SearchState and GlobalSearchState + +As with other components, we no longer store instances of `forum/components/Search`. As such, every `Search` component instance should be paired with a `forum/states/SearchState` instance. + +At the minimum, `SearchState` contains the following methods: + +- getValue +- setValue +- clear +- cache (adds a searched value to cache, meaning that we don't need to search for its results again) +- isCached (checks if a value has been searched for before) + +All of these methods have been moved from `Search` to `SearchState`. Additionally, Search's `stickyParams`, `params`, `changeSort`, `getInitialSearch`, and `clearInitialSearch` methods have been moved to `forum/states/GlobalSearchState`, which is now available via `app.search`. + +To use a custom search, you'll want to: + +1. Possibly create a custom subclass of `SearchState` +2. Create a custom subclass of `Search`, which overrides the `selectResult` method to handle selecting results as needed by your use case, and modify the `sourceItems` methods to contain the search sources you need. + +#### moment -> dayjs + +The `moment` library has been removed, and replaced by the `dayjs` library. The global `moment` can still be used for now, but is deprecated. `moment` and `dayjs` have very similar APIs, so very few changes will be needed. Please see the dayjs documentation [for more information](https://day.js.org/en/) on how to use it. + +#### Subtree Retainer + +`SubtreeRetainer` is a util class that makes it easier to avoid unnecessary redraws by keeping track of some pieces of data. +When called, it checks if any of the data has changed; if not, it indicates that a redraw is not necessary. + +In mithril 0.2, its `retain` method returned a [subtree retain directive](https://mithril.js.org/archive/v0.1.25/mithril.render.html#subtree-directives) if no redraw was necessary. + +In mithril 2, we use its `needsRebuild` method in combination with `onbeforeupdate`. For instance: + +```js +class CustomComponent extends Component { + oninit(vnode) { + super.oninit(vnode); + + this.showContent = false; + + this.subtree = new SubtreeRetainer( + () => this.showContent, + ) + } + + onbeforeupdate() { + // If needsRebuild returns true, mithril will diff and redraw the vnode as usual. Otherwise, it will skip this redraw cycle. + // In this example, this means that this component and its children will only be redrawn when extra content is toggled. + return this.subtree.needsRebuild(); + } + + view(vnode) { + return
+ +

Hello World!{this.showContent ? ' Extra Content!' : ''}

+
; + } +} +``` + +#### attrs() method + +Previously, some components would have an attrs() method, which provided an extensible way to provide attrs to the top-level child vnode returned by `view()`. For instance, + +```js +class CustomComponent extends Component { + view() { + return

Hello World!

; + } + + attrs() { + return { + className: 'SomeClass', + onclick: () => console.log('click'), + }; + } +} +``` + +Since `this.attrs` is now used for attrs passed in from parent components, `attrs` methods have been renamed to `elementAttrs`. + +#### Children and .component + +Previously, an element could be created with child elements by passing those in as the `children` prop: + +```js +Button.component({ + className: 'Button Button--primary', + children: 'Button Text' +}); +``` + +This will no longer work, and will actually result in errors. Instead, the 2nd argument of the `component` method should be used: + +```js +Button.component({ + className: 'Button Button--primary' +}, 'Button Text'); +``` + +Children can still be passed in through JSX: + +```js + +``` + +#### Tag attr + +Because mithril uses 'tag' to indicate the actual html tag (or component class) used for a vnode, you can no longer pass `tag` as an attr to components +extending Flarum's `Component` helper class. The best workaround here is to just use another name for this attr. + +#### affixSidebar + +The `affixSidebar` util has been removed. Instead, if you want to affix a sidebar, wrap the sidebar code in an `AffixedSidebar` component. For instance, + +```js +class OldWay extends Component { + view() { + return
+
+
+ +
Actual Page Content
+
+
+
; + } +} + +class NewWay extends Component { + view() { + return
+
+
+ + + +
Actual Page Content
+
+
+
; + } +} +``` + +#### Fragment + +**Warning: For Advanced Use Only** + +In some rare cases, we want to have extremely fine grained control over the rendering and display of some significant chunks of the DOM. These are attached with `m.render`, and do not experience automated redraws. Current use cases in core and bundled extensions are: + +- The "Reply" button that shows up when selecting text in a post +- The mentions autocomplete menu that shows up when typing +- The emoji autocomplete menu that shows up when typing + +For this purpose, we provide a helper class (`common/Fragment`), of which you can create an instance, call methods, and render via `m.render(DOM_ROOT, fragmentInstance.render())`. The main benefit of using the helper class is that it allows you to use lifecycle methods, and to access the underlying DOM via `this.$()`, like you would be able to do with a component. + +This should only be used when absolutely necessary. If you are unsure, you probably don't need it. If the goal is to not store component instances, the "state pattern" as described above is preferable. + +### Required Frontend Changes Recap + +Each of these changes has been explained above, this is just a recap of major changes for your convenience. + +- Component Methods: + - `view()` -> `view(vnode)` + - Lifecycle + - `init()` -> `oninit(vnode)` + - `config()` -> Lifecycle hooks `oncreate(vnode)` / `onupdate(vnode)` + - `context.onunload()` -> `onremove()` + - `SubtreeRetainer` -> `onbeforeupdate()` + - if present, `attrs()` method needs to be renamed -> convention `elementAttrs()` + - building component with `MyComponent.component()` -> `children` is now second parameter instead of a named prop/attr (first argument) -> JSX preferred +- Routing + - `m.route()` -> `m.route.get()` + - `m.route(name)` -> `m.route.set(name)` + - register routes with page class, not instance + - special case when passing props + - `` -> `` +- AJAX + - `m.request({...})` -> `data:` key split up into `body:` and `params:` + - `m.deferred` -> native `Promise` +- Redrawing + - `m.redraw(true)` -> `m.redraw.sync()` + - `m.redraw.strategy('none')` -> `e.redraw = false` in event handler + - `m.lazyRedraw()` -> `m.redraw()` + +#### Deprecated changes + +For the following changes, we currently provide a backwards-compatibility layer. +This will be removed in time for the stable release. +The idea is to let you release a new version that's compatible with Beta 14 to your users as quickly as possible. +When you have taken care of the changes above, you should be good to go. +For the following changes, we have bought you time until the stable release. +Considering you have to make changes anyway, why not do them now? + +- `this.props` -> `this.attrs` +- static `initProps()` -> static `initAttrs()` +- `m.prop` -> `flarum/utils/Stream` +- `m.withAttr` -> `flarum/utils/withAttr` +- `moment` -> `dayjs` + +## Backend (PHP) + +### New Features + +#### Extension Dependencies + +Some extensions are based on, or add features to, other extensions. +Prior to this release, there was no way to ensure that those dependencies were enabled before the extension that builds on them. +Now, you cannot enable an extension unless all of its dependencies are enabled, and you cannot disable an extension if there are other enabled extensions depending on it. + +So, how do we specify dependencies for an extension? Well, all you need to do is add them as composer dependencies to your extension's `composer.json`! For instance, if we have an extension that depends on Tags and Mentions, our `composer.json` will look like this: + +```json +{ + "name": "my/extension", + "description": "Cool New Extension", + "type": "flarum-extension", + "license": "MIT", + "require": { + "flarum/core": "^0.1.0-beta.14", + "flarum/tags": "^0.1.0-beta.14", // Will mark tags as a dependency + "flarum/mentions": "^0.1.0-beta.14", // Will mark mentions as a dependency + } + // other config +} +``` + +#### View Extender + +Previously, when extensions needed to register Laravel Blade views, they could inject a view factory in `extend.php` and call it's `addNamespace` method. For instance, + +```php +// extend.php +use Illuminate\Contracts\View\Factory; + +return [ + function (Factory $view) { + $view->addNamespace(NAME, RELATIVE PATH); + } +] +``` + +This should NOT be used, as it will break views for all extensions that boot after yours. Instead, the `View` extender should be used: + +```php +// extend.php +use Flarum\Extend\View; + +return [ + (new View)->namespace(NAME, RELATIVE PATH); +] +``` + +#### Application and Container + +Although Flarum uses multiple components of the Laravel framework, it is not a pure Laravel system. In beta 14, the `Flarum\Foundation\Application` class no longer implements `Illuminate\Contracts\Foundation\Application`, and no longer inherits `Illuminate\Container\Container`. Several things to note: + +- The `app` helper now points to an instance of `Illuminate\Container\Container`, not `Flarum\Foundation\Application`. You might need to resolve things through the container before using them: for instance, `app()->url()` will no longer work; you'll need to resolve or inject an instance of `Flarum\Foundation\Config` and use that. +- Injected or resolved instances of `Flarum\Foundation\Application` can no longer resolve things through container methods. `Illuminate\Container\Container` should be used instead. +- Not all public members of `Illuminate\Contracts\Foundation\Application` are available through `Flarum\Foundation\Application`. Please refer to our [API docs on `Flarum\Foundation\Application`](https://api.docs.flarum.org/php/master/flarum/foundation/application) for more information. + +#### Other Changes + +- We are now using Laravel 6. Please see [Laravel's upgrade guide](https://laravel.com/docs/6.x/upgrade) for more information. Please note that we do not use all of Laravel. +- Optional params in url generator now work. For instance, the url generator can now properly generate links to posts in discussions. +- A User Extender has been added, which replaces the deprecated `PrepareUserGroups` and `GetDisplayName` events. +- Error handler middleware can now be manipulated by the middleware extender through the `add`, `remove`, `replace`, etc methods, just like any other middleware. +- `Flarum/Foundation/Config` and `Flarum/Foundation/Paths` can now be injected where needed; previously their data was accessible through `Flarum/Foundation/Application`. + +### Deprecations + +- `url` provided in `config.php` is now an array, accessible via `$config->url()`, for an instance of `Config` - [PR](https://github.com/flarum/core/pull/2271#discussion_r475930358) +- AssertPermissionTrait has been deprecated - [Issue](https://github.com/flarum/core/issues/1320) +- Global path helpers and path methods of `Application` have been deprecated, the injectable `Paths` class should be used instead - [PR](https://github.com/flarum/core/pull/2155) +- `Flarum\User\Event\GetDisplayName` has been deprecated, the `displayNameDriver` method of the `User` extender should be used instead - [PR](https://github.com/flarum/core/pull/2174) + +### Removals + +- Do NOT use the old closure notation for configuring view namespaces. This will break all extensions that boot after your extension. The `View` extender MUST be used instead. +- app()->url() will no longer work: [`Flarum\Http\UrlGenerator`](routes.md) should be injected and used instead. An instance of `Flarum\Http\UrlGenerator` is available in `blade.php` templates via `$url`. +- As a part of the Laravel 6 upgrade, the [`array_` and `str_` helpers](https://laravel.com/docs/6.x/upgrade#helpers) have been removed. +- The Laravel translator interface has been removed; the Symfony translator interface should be used instead: `Symfony\Component\Translation\TranslatorInterface` +- The Mandrill mail driver is no longer provided in Laravel 6, and has been removed. +- The following events deprecated in Beta 13 [have been removed](https://github.com/flarum/core/commit/7d1ef9d89161363d1c8dea19cf8aebb30136e9e3#diff-238957b67e42d4e977398cd048c51c73): + - `AbstractConfigureRoutes` + - `ConfigureApiRoutes` - Use the `Routes` extender instead + - `ConfigureForumRoutes` - Use the `Frontend` or `Routes` extenders instead + - `ConfigureLocales` - Use the `LanguagePack` extender instead + - `ConfigureModelDates` - Use the `Model` extender instead + - `ConfigureModelDefaultAttributes` - Use the `Model` extender instead + - `GetModelRelationship` - Use the `Model` extender instead + - `Console\Event\Configuring` - Use the `Console` extender instead + - `BioChanged` - User bio has not been a core feature for several releases diff --git a/versioned_docs/version-1.x/extend/update-b15.md b/versioned_docs/version-1.x/extend/update-b15.md new file mode 100644 index 000000000..c815ca9c2 --- /dev/null +++ b/versioned_docs/version-1.x/extend/update-b15.md @@ -0,0 +1,60 @@ +# Updating For Beta 15 + +Beta 15 features multiple new extenders, a total redesign of the admin dashboard, and several other interesting new features for extensions. As before, we have done our best to provide backwards compatibility layers, and we recommend switching away from deprecated systems as soon as possible to make your extensions more stable. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## New Features / Deprecations + +### Extenders + +- `Flarum\Api\Event\WillGetData` and `Flarum\Api\Event\WillSerializeData` have been deprecated, the `ApiController` extender should be used instead +- `Flarum\Api\Event\Serializing` and `Flarum\Event\GetApiRelationship` have been deprecated, the `ApiSerializer` extender should be used instead +- `Flarum\Formatter\Event\Parsing` has been deprecated, the `parse` method of the `Formatter` extender should be used instead +- `Flarum\Formatter\Event\Rendering` has been deprecated, the `render` method of the `Formatter` extender should be used instead +- `Flarum\Notification\Event\Sending` has been deprecated, the `driver` method of the `Notification` extender should be used instead + - Please note that the new notification driver system is not an exact analogue of the old `Sending` event, as it can only add new drivers, not change the functionality of the default notification bell alert driver. If your extension needs to modify **how** or **to whom** notifications are sent, you may need to replace `Flarum\Notification\NotificationSyncer` on the service provider level +- `Flarum\Event\ConfigureNotificationTypes` has been deprecated, the `type` method of the `Notification` extender should be used instead +- `Flarum\Event\ConfigurePostTypes` has been deprecated, the `type` method of the `Post` extender should be used instead +- `Flarum\Post\Event\CheckingForFlooding` has been deprecated, as well as `Flarum\Post\Floodgate`. They have been replaced with a middleware-based throttling system that applies to ALL requests to /api/*, and can be configured via the `ThrottleApi` extender. Please see our [api-throttling](api-throttling.md) documentation for more information. +- `Flarum\Event\ConfigureUserPreferences` has been deprecated, the `registerPreference` method of the `User` extender should be used instead +- `Flarum\Foundation\Event\Validating` has been deprecated, the `configure` method of the `Validator` extender should be used instead + +- The Policy system has been reworked a bit to be more intuitive. Previously, policies contained both actual policies, which determine whether a user can perform some ability, and model visibility scopers, which allowed efficient restriction of queries to only items that users have access to. See the [authorization documentation](authorization.md) for more information on how to use the new systems. Now: + - `Flarum\Event\ScopeModelVisibility` has been deprecated. New scopers can be registered via the `ModelVisibility` extender, and any `Eloquent\Builder` query can be scoped by calling the `whereVisibleTo` method on it, with the ability in question as an optional 2nd argument (defaults to `view`). + - `Flarum\Event\GetPermission` has been deprecated. Policies can be registered via the `Policy` extender. `Flarum\User\User::can` has not changed. Please note that the new policies must return one of `$this->allow()`, `$this->deny()`, `$this->forceAllow()`, `$this->forceDeny()`, not a boolean. + +- A `ModelUrl` extender has been added, allowing new slug drivers to be registered. This accompanies Flarum's new slug driving system, which allows for extensions to define custom slugging strategies for sluggable models. The extender supports sluggable models outside of Flarum core. Please see our [model slugging](slugging.md) documentation for more information. +- A `Settings` extender has been added, whose `serializeToForum` method makes it easy to serialize a setting to the forum. +- A `ServiceProvider` extender has been added. This should be used with extreme caution for advanced use cases only, where there is no alternative. Please note that the service provider layer is not considered public API, and is liable to change at any time, without notice. + +### Admin UX Redesign + +The admin dashboard has been completely redesigned, with a focus on providing navbar pages for each extension. The API for extensions to register settings, permissions, and custom pages has also been greatly simplified. You can also now update your extension's `composer.json` to provide links for funding, support, website, etc that will show up on your extension's admin page. Please see [our Admin JS documentation](admin.md) for more information on how to use the new system. + +### Other New Features + +- On the backend, the route name is now available via `$request->getAttribute('routeName')` for controllers, and for middleware that run after `Flarum\Http\Middleware\ResolveRoute.php`. +- `Flarum\Api\Controller\UploadImageController.php` can now be used as a base class for controllers that upload images (like for the logo and favicon). +- Automatic browser scroll restoration can now be disabled for individual pages [see our frontend page documentation for more info](frontend-pages.md). + +## Breaking Changes + +- The following deprecated frontend BC layers were removed: + - `momentjs` no longer works as an alias for `dayjs` + - `this.props` and `this.initProps` no longer alias `this.attrs` and `this.initAttrs` for the `Component` base class + - `m.withAttr` and `m.stream` no longer alias `flarum/utils/withAttr` and `flarum/utils/Stream` + - `app.cache.discussionList` has been removed + - `this.content` and `this.editor` have been removed from `ComposerBody` + - `this.component`, `this.content`, and `this.value` have been removed from `ComposerState` +- The following deprecated backend BC layers were removed: + - The `publicPath`, `storagePath`, and `vendorPath` methods of `Flarum\Foundation\Application` have been removed + - The `base_path`, `public_path`, and `storage_path` global helpers have been removed + - The `getEmailSubject` method of `Flarum\Notification\MailableInterface` MUST now take a translator instance as an argument + - `Flarum\User\AssertPermissionTrait` has been removed, the analogous methods on `Flarum\User\User` should be used instead + - The `Flarum\Event\PrepareUserGroups` event has been removed, use the `User` extender instead + - The `Flarum\User\Event\GetDisplayName` event has been removed, use the display name driver feature of the `User` extender instead diff --git a/versioned_docs/version-1.x/extend/update-b16.md b/versioned_docs/version-1.x/extend/update-b16.md new file mode 100644 index 000000000..fb63e6b42 --- /dev/null +++ b/versioned_docs/version-1.x/extend/update-b16.md @@ -0,0 +1,141 @@ +# Updating For Beta 16 + +Beta 16 finalizes the PHP extender API, introduces a testing library and JS typings, switches to using namespaces for JS imports, increases extension dependency robustness, and allows overriding routes, among other features. + +:::tip + +If you need help applying these changes or using new features, please start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## Frontend + +- A new editor driver abstraction has been introduced, which allows extensions to override the default textarea-based editor with more advanced solutions. +- The `TextEditor` and `TextEditorButton` components, as well as the `BasicEditorDriver` util (which replaces `SuperTextarea`) have been moved from `forum` to `common`. +- The `forum`, `admin`, and `common` namespaces should be used when importing. So instead of `import Component from 'flarum/Component'`, use `import Component from 'flarum/common/Component`. Support for the old import styles will be deprecated through the stable release, and removed with Flarum 2.0. +- A typing library has been released to support editor autocomplete for frontend development, and can be installed in your dev environment via `npm install --save-dev flarum@0.1.0-beta.16`. +- Extension categories have been simplified down to `feature`, `theme`, and `language`. + +## Backend + +### Extenders + +- All extenders that support callbacks/closures now support global functions like `'boolval'` and array-type functions like `[ClassName::class, 'methodName']`. +- The `Settings` extender's `serializeToFrontend` method now supports a default value as the 4th argument. +- The `Event` extender now supports registering subscribers for multiple events at once via a `subscribe` method. +- The `Notification` extender now has a `beforeSending` method, which allows you to adjust the list of recipients before a notification is sent. +- The `mutate` method of `ApiSerializer` has been deprecated, and renamed to `attributes`. +- `remove` methods on the `Route` and `Frontend` extenders can be used to remove (and then replace) routes. +- A `ModelPrivate` extender replaces the `GetModelIsPrivate` event, which has been deprecated. +- Methods on the `Auth` extender replace the `CheckingPassword` event, which has been deprecated. +- All search-related events are now deprecated in favor of the `SimpleFlarumSearch` and `Filter` extenders; this is explained in more detail below. + +### Laravel and Symfony + +Beta 16 upgrades from v6.x to v8.x of Laravel components and v4 to v5 of Symfony components. Please see the respective upgrade guides of each for changes you might need to make to your extensions. +The most applicable change is the deprecation of `Symfony\Component\Translation\TranslatorInterface` in favor of `Symfony\Contracts\Translation\TranslatorInterface`. The former will be removed in beta 17. + +### Helper Functions + +The remaining `app` and `event` global helper functions have been deprecated. `app` has been replaced with `resolve`, which takes the name of a container binding and resolves it through the container. + +Since some Flarum extensions use Laravel libraries that assume some global helpers exist, we've recreated some commonly used helpers in the [flarum/laravel-helpers](https://github.com/flarum/laravel-helpers) package. These helpers should NOT be used directly in Flarum extension code; they are available so that Laravel-based libraries that expect them to exist don't malfunction. + +### Search Changes + +As part of our ongoing efforts to make Flarum's search system more flexible, we've made several refactors in beta 16. +Most notably, filtering and searching are now treated as different mechanisms, and have separate pipelines and extenders. +Essentially, if a query has a `filter[q]` query param, it will be treated as a search, and all other filter params will be ignored. Otherwise, it will be handled by the filtering system. This will eventually allow searches to be handled by alternative drivers (provided by extensions), such as ElasticSearch, without impacting filtering (e.g. loading recent discussions). Classes common to both systems have been moved to a `Query` namespace. + +Core's filtering and default search (named SimpleFlarumSearch) implementations are quite similar, as both are powered by the database. `List` API controllers call the `search` / `filter` methods on a resource-specific subclass of `Flarum\Search\AbstractSearcher` or `Flarum\Filter\AbstractFilterer`. Arguments are an instance of `Flarum\Query\QueryCriteria`, as well as sort, offset, and limit information. Both systems return an instance of `Flarum\Query\QueryResults`, which is effectively a wrapper around a collection of Eloquent models. + +The default systems are also somewhat similar in their implementation. `Filterer`s apply Filters (implementing `Flarum\Filter\FilterInterface`) based on query params in the form `filter[FILTER_KEY] = FILTER_VALUE` (or `filter[-FILTER_KEY] = FILTER_VALUE` for negated filters). SimpleFlarumSearch's `Searcher`s split the `filter[q]` param by spaces into "terms", apply Gambits (implementing `Flarum\Search\GambitInterface`) that match the terms, and then apply a "Fulltext Gambit" to search based on any "terms" that don't match an auxiliary gambit. Both systems then apply sorting, an offset, and a result count limit, and allow extensions to modify the query result via `searchMutators` or `filterMutators`. + +Extensions add gambits and search mutators and set fulltext gambits for `Searcher` classes via the `SimpleFlarumSearch` extender. They can add filters and filter mutators to `Filterer` classes via the `Filter` extender. + +With regards to upgrading, please note the following: + +- Search mutations registered by listening to the `Searching` events for discussions and users will be applied as to searches during the search mutation step via a temporary BC layer. They WILL NOT be applied to filters. This is a breaking change. These events have been deprecated. +- Search gambits registered by listening to the `ConfigureUserGambits` and `ConfigureDiscussionGambits` events will be applied to searcher via a temporary BC layer. They WILL NOT be applied to filters. This is a breaking change. These events have been deprecated. +- Post filters registered by listening to the `ConfigurePostsQuery` events will be applied to post filters via a temporary BC layer. That event has been deprecated. + +### Testing Library + +The `flarum/testing` package provides utils for PHPUnit-powered automated backend tests. See the [testing documentation](testing.md) for more info. + +### Optional Dependencies + +Beta 15 introduced "extension dependencies", which require any extensions listed in your extension's `composer.json`'s `require` section to be enabled before your extension can be enabled. + +With beta 16, you can specify "optional dependencies" by listing their composer package names as an array in your extension's `extra.flarum-extension.optional-dependencies`. Any enabled optional dependencies will be booted before your extension, but aren't required for your extension to be enabled. + +### Access Token and Authentication Changes + +#### Extension API changes + +The signature to various method related to authentication have been changed to take `$token` as parameter instead of `$userId`. Other changes are the result of the move from `$lifetime` to `$type` + +- `Flarum\Http\AccessToken::generate($userId)` no longer accepts `$lifetime` as a second parameter. Parameter has been kept for backward compatibility but has no effect. It will be removed in beta 17. +- `Flarum\Http\RememberAccessToken::generate($userId)` should be used to create remember access tokens. +- `Flarum\Http\DeveloperAccessToken::generate($userId)` should be used to create developer access tokens (don't expire). +- `Flarum\Http\SessionAccessToken::generate()` can be used as an alias to `Flarum\Http\AccessToken::generate()`. We might deprecate `AccessToken::generate()` in the future. +- `Flarum\Http\Rememberer::remember(ResponseInterface $response, AccessToken $token)`: passing an `AccessToken` has been deprecated. Pass an instance of `RememberAccessToken` instead. As a temporary compatibility layer, passing any other type of token will convert it into a remember token. In beta 17 the method signature will change to accept only `RememberAccessToken`. +- `Flarum\Http\Rememberer::rememberUser()` has been deprecated. Instead you should create/retrieve a token manually with `RememberAccessToken::generate()` and pass it to `Rememberer::remember()` +- `Flarum\Http\SessionAuthenticator::logIn(Session $session, $userId)` second parameter has been deprecated and is replaced with `$token`. Backward compatibility is kept. In beta 17, the second parameter method signature will change to `AccessToken $token`. +- `AccessToken::generate()` now saves the model to the database before returning it. +- `AccessToken::find($id)` or `::findOrFail($id)` can no longer be used to find a token, because the primary key was changed from `token` to `id`. Instead you can use `AccessToken::findValid($tokenString)` +- It's recommended to use `AccessToken::findValid($tokenString): AccessToken` or `AccessToken::whereValid(): Illuminate\Database\Eloquent\Builder` to find a token. This will automatically scope the request to only return valid tokens. On forums with low activity this increases the security since the automatic deletion of outdated tokens only happens every 50 requests on average. + +#### Symfony session changes + +If you are directly accessing or manipulating the Symfony session object, the following changes have been made: + +- `user_id` attribute is no longer used. `access_token` has been added as a replacement. It's a string that maps to the `token` column of the `access_tokens` database table. + +To retrieve the current user from inside a Flarum extension, the ideal solution which was already present in Flarum is to use `$request->getAttribute('actor')` which returns a `User` instance (which might be `Guest`) + +To retrieve the token instance from Flarum, you can use `Flarum\Http\AccessToken::findValid($tokenString)` + +To retrieve the user data from a non-Flarum application, you'll need to make an additional database request to retrieve the token. The user ID is present as `user_id` on the `access_tokens` table. + +#### Token creation changes + +The `lifetime` property of access tokens has been removed. Tokens are now either `session` tokens with 1h lifetime after last activity, or `session_remember` tokens with 5 years lifetime after last activity. + +The `remember` parameter that was previously available on the `POST /login` endpoint has been made available on `POST /api/token`. It doesn't return the remember cookie itself, but the token returned can be used as a remember cookie. + +The `lifetime` parameter of `POST /api/token` has been deprecated and will be removed in Flarum beta 17. Partial backward compatibility has been provided where a `lifetime` value longer than 3600 seconds is interpreted like `remember=1`. Values lower than 3600 seconds result in a normal non-remember token. + +New `developer` tokens that don't expire have been introduced, however they cannot be currently created through the REST API. Developers can create developer tokens from an extension using `Flarum\Http\DeveloperAccessToken::generate($userId)`. + +If you manually created tokens in the database from outside Flarum, the `type` column is now required and must contain `session`, `session_remember` or `developer`. Tokens of unrecognized type cannot be used to authenticate, but won't be deleted by the garbage collector either. In a future version extensions will be able to register custom access token types. + +#### Token usage changes + +A [security issue in Flarum](https://github.com/flarum/core/issues/2075) previously caused all tokens to never expire. This had limited security impact due to tokens being long unique characters. However custom integrations that saved a token in an external database for later use might find the tokens no longer working if they were not used recently. + +If you use short-lived access tokens for any purpose, take note of the expiration time of 1h. The expiration is based on the time of last usage, so it will remain valid as long as it continues to be used. + +Due to the large amount of expired tokens accumulated in the database and the fact most tokens weren't ever used more than once during the login process, we have made the choice to delete all access tokens a lifetime of 3600 seconds as part of the migration, All remaining tokens have been converted to `session_remember` tokens. + +#### Remember cookie + +The remember cookie still works like before, but a few changes have been made that could break unusual implementations. + +Now only access tokens created with `remember` option can be used as remember cookie. Any other type of token will be ignored. This means if you create a token with `POST /api/token` and then place it in the cookie manually, make sure you set `remember=1` when creating the token. + +#### Web session expiration + +In previous versions of Flarum, a session could be kept alive forever until the Symfony session files were deleted from disk. + +Now sessions are linked to access tokens. A token being deleted or expiring will automatically end the linked web session. + +A token linked to a web session will now be automatically deleted from the database when the user clicks logout. This prevents any stolen token from being re-used, but it could break custom integration that previously used a single access token in both a web session and something else. + +### Miscellaneous + +- The IP address is now available in requests via `$request->getAttribute('ipAddress')` +- Policies can now return `true` and `false` as aliases for `$this->allow()` and `$this->deny()`, respectively. +- The `user.edit` permission has been split into `user.editGroups`, `user.editCredentials` (for email, username, and password), and `user.edit` (for other attributes). +- There are now permissions (`bypassTagCounts`) that allow users to bypass tag count requirements. +- Flarum now supports PHP 7.3 - PHP 8.0, with support for PHP 7.2 officially dropped. diff --git a/versioned_docs/version-1.x/extend/update-b8.md b/versioned_docs/version-1.x/extend/update-b8.md new file mode 100644 index 000000000..eaf3b874f --- /dev/null +++ b/versioned_docs/version-1.x/extend/update-b8.md @@ -0,0 +1,114 @@ +# Updating For Beta 8 + +All extensions will need to be refactored in order to work with beta 8. Here are the main things you will need to do in order to make your extension compatible. + +:::caution + +This guide is not comprehensive. You may encounter some changes we haven't documented. If you need help, start a discussion on the [community forum](https://discuss.flarum.org/t/extensibility) or [Discord chat](https://flarum.org/discord/). + +::: + +## PHP Namespaces + +Beta 8 comes with large changes to the overall structure of the PHP backend. You will need to look through [this list](https://discuss.flarum.org/d/6572-help-us-namespace-changes) of namespace changes and make changes to your extension accordingly. + +[This script](https://gist.github.com/tobyzerner/55e7c05c95404e5efab3a9e43799d375) can help you to automate most of the namespace changes. Of course, you should still test your extension after running the script as it may miss something. + +## Database Naming + +Many database columns and JSON:API attributes have been renamed to conform to a [convention](/contributing.md#database). You will need to update any instances where your extension interacts with core data. You can see the changes in [#1344](https://github.com/flarum/core/pull/1344/files). + +## Extenders + +Beta 8 introduces a new concept called **extenders** that replace the most common event listeners. You can learn more about how they work in the [updated extension docs](start.md#extenders). + +`bootstrap.php` has been renamed to `extend.php` and returns an array of extender instances and functions: + +```php +use Flarum\Extend; + +return [ + (new Extend\Frontend('forum')) + ->js(__DIR__.'/js/dist/forum.js') + ->css(__DIR__.'/less/forum.less') + ->route('/t/{slug}', 'tag') + ->route('/tags', 'tags'), + + function (Dispatcher $events) { + $events->subscribe(Listener\AddForumTagsRelationship::class); + } +] +``` + +If you're listening for any of the following events, you'll need to update your code to use an extender instead. See the relevant docs for more information. + +| Event | Extender | +| ----------------------------------- | ------------------------- | +| `Flarum\Event\ConfigureFormatter`* | `Flarum\Extend\Formatter` | +| `Flarum\Event\ConfigureWebApp`* | `Flarum\Extend\Frontend` | +| `Flarum\Event\ConfigureClientView`* | `Flarum\Extend\Frontend` | +| `Flarum\Event\ConfigureLocales` | `Flarum\Extend\Locales` | +| `Flarum\Event\ConfigureApiRoutes` | `Flarum\Extend\Routes` | +| `Flarum\Event\ConfigureForumRoutes` | `Flarum\Extend\Routes` | + +_\* class no longer exists_ + +## JavaScript Tooling + +Previously Flarum and its extensions used a custom Gulp workflow to compile ES6 source code into something that browsers could understand. Beta 8 switches to a more conventional approach with Webpack. + +You will need to tweak the structure of your extension's `js` directory. Currently, your JS file hierarchy looks something like the following: + +``` +js +├── admin +│ ├── src +│ │ └── main.js +│ ├── dist +│ │ └── extension.js +│ ├── Gulpfile.js +│ └── package.json +└── forum + ├── src + │ └── main.js + ├── dist + │ └── extension.js + ├── Gulpfile.js + └── package.json +``` + +You'll need to make the following changes: + +1. Update `package.json` and create `webpack.config.js`, `forum.js`, and `admin.js` files using [these templates](frontend.md#transpilation). + +2. Inside your `admin` and `forum` *folders*, delete `Gulpfile.js`, `package.json`, and `dist`. Then inside each `src` folder, rename `main.js` to `index.js`. Now move all of the `src` files outside of `src` folder and delete it. + +3. In the root `js` folder create a folder called `src` and move your `admin` and `forum` *folders* into it. + +4. While still in your root `js` folder, run `npm install` and then `npm run build` to build the new JS dist files. + +If everything went right, your folder structure should look something like this: + +``` +js +├── src +│ ├── admin +│ │ └── index.js +│ └── forum +│ └── index.js +├── dist +│ ├── admin.js +│ ├── admin.js.map +│ ├── forum.js +│ └── forum.js.map +├── admin.js +├── forum.js +├── package.json +└── webpack.config.js +``` + +Take a look at the [bundled extensions](https://github.com/flarum) for more examples. + +## Font Awesome Icons + +Beta 8 upgrades to Font Awesome 5, in which icon class names have changed. The `flarum/helpers/icon` helper now requires the **full Font Awesome icon class names** to be passed, eg. `fas fa-bolt`. diff --git a/versioned_docs/version-1.x/extend/views.md b/versioned_docs/version-1.x/extend/views.md new file mode 100644 index 000000000..e82567f11 --- /dev/null +++ b/versioned_docs/version-1.x/extend/views.md @@ -0,0 +1,67 @@ +# Views and Blade + +Although the Flarum UI you know and love is powered by our [Mithril frontend](frontend), +server-side generated templates are still used throughout Flarum. Most notably, the HTML skeleton of the forum, which includes various SEO meta tags, as well as the no-js view of the forum, is implemented through the Views and Blade systems. + +[Blade](https://laravel.com/docs/8.x/blade) is Laravel's templating engine, which allows you to conveniently generate HTML (or other static content) from PHP. +It's the same idea as [Jinja](https://jinja.palletsprojects.com/en/3.0.x/) or [EJS](https://ejs.co/). +[Views](https://laravel.com/docs/8.x/views) are Laravel's system for organizing/registering Blade templates, and also includes utilities for rendering them and providing them with variables. + +For our purposes, views are directories containing `.blade.php` template files (possibly contained in subdirectories). + +## Adding Views + +You will need to tell the view factory where it can find your extension's view files by adding a `View` extender to `extend.php`: + +```php +use Flarum\Extend; +use Illuminate\Contracts\View\Factory; + +return [ + (new Extend\View) + ->namespace('acme.hello-world', __DIR__.'/views'), +]; +``` + + +## Blade Templates + +To learn about the syntax for Blade templates, read [Laravel's documentation](https://laravel.com/docs/8.x/blade). + +Once you've set up your views, you can render them to strings: + +```php +// Here, $view is of type `Illuminate\Contracts\View\Factory` +$renderedString = $view->make('acme.hello-world::greeting')->render(); + +// You can also pass variables to the view: +$renderedString = $view->make('acme.hello-world::greeting', ['varName' => true])->render(); +``` + +You can obtain the view factory instance through dependency injection. + +The format is `"VIEW_NAMESPACE::VIEW_NAME"`. If the view folder is organized as subdirectories, replace `/` with `.` in the pack. +So if you have a file at `"forum/error.blade.php"` in a namespace called `"custom-views"`, you would use `"custom-views::forum.error"`. + +Note that all Blade templates rendered this way automatically have access to the following variables: + +- `$url`: a [URL generator](routes#generating-urls) instance. +- `$translator`: a [Translator](i18n#server-side-translation) instance. +- `$settings`: a [SettingsInterface](settings) instance. +- `$slugManager`: a [SlugManager](slugging) instance. + +Additionally, templates used by [content logic](routes#content) have access to `$forum`, which represents the [Forum API Document's attributes](https://github.com/flarum/framework/blob/main/framework/core/src/Api/Serializer/ForumSerializer.php#L19). + +## Overriding Views + +If you want to override templates added by core or extensions, set up a view folder structure matching the one you are trying to override, containing just the files you are trying to override. Then use the `View` extender's `extendNamespace` method: + +```php +use Flarum\Extend; +use Illuminate\Contracts\View\Factory; + +return [ + (new Extend\View) + ->extendNamespace('acme.hello-world', __DIR__.'/override_views'); +]; +``` diff --git a/versioned_docs/version-1.x/extenders.md b/versioned_docs/version-1.x/extenders.md new file mode 100644 index 000000000..60efb7fda --- /dev/null +++ b/versioned_docs/version-1.x/extenders.md @@ -0,0 +1,25 @@ +# Local Extenders + +If there are customizations you want to make to your site without distributing an entire extension, you can do so by using **local extenders**. Each Flarum installation comes with an `extend.php` file where you can add extender instances, just like in a full extension. + +See our [extension documentation](extend/start.md) for more information about extenders (and even an [example of a local extender](extend/start.md#hello-world)). + +If you need to create new files (when adding a custom class to be imported for extenders), you'll need to adjust your composer.json a bit. +Add the following: + +```json +"autoload": { + "psr-4": { + "App\\": "app/" + } +}, +``` + +Now you can create new PHP files in an `app` subdirectory using the `App\...` namespace. + +:::tip Local Extenders vs Extensions + +Local extenders can be good for small tweaks, but if you need large customizations, an extension might be a better choice: +a separate codebase, cleaner handling of many files, developer tooling, and the ability to easily open source are big benefits. + +::: diff --git a/versioned_docs/version-1.x/extensions.md b/versioned_docs/version-1.x/extensions.md new file mode 100644 index 000000000..2ea6b04e2 --- /dev/null +++ b/versioned_docs/version-1.x/extensions.md @@ -0,0 +1,119 @@ +# Extensions + +Flarum is minimalistic, but it's also highly extensible. In fact, most of the features that ship with Flarum are actually extensions! + +This approach makes Flarum extremely customizable: You can disable any features you don't need, and install other extensions to make your forum perfect for your community. + +For more information on Flarum's philosophy on what features we include in core, or if you're looking to make your own extension, please see our [extension documentation](extend/README.md). +This article will focus on managing extensions from a forum admin's perspective. + +## Extension Manager + +The extension manager is an extension that comes bundled with Flarum when installed via an archive. It provides a graphical interface for installing and updating both extensions and Flarum itself. + +If you do not have the extension manager installed and you wish to install it, you can do so by running the following command in your Flarum directory: + +```bash +composer require flarum/extension-manager:"*" +``` + +:::warning + +The extension manager allows an admin user to install any composer package. Only install the extension manager if you trust all of your forum admins with such permissions. + +::: + +![extension manager admin page](https://github.com/flarum/docs/assets/20267363/d0e1f7a5-e194-4acd-af63-7b8ddd95c26b) + + +## Finding Extensions + +Flarum has a wide ecosystem of extensions, most of which are open source and free. To find new and awesome extensions, visit the [Extensions](https://discuss.flarum.org/t/extensions) tag on Flarum's community forums. The unofficial [Extiverse extension database](https://extiverse.com/) is also a great resource. + +## Installing Extensions + +### Through the interface + +Using the extension manager extension, you can install extensions directly from the admin dashboard. Once you have browsed the list of available extensions from the links above, and found one you want to install, you can install it by entering the extension's composer package name into the extension manager's installation input. + +![Installing an extension](/en/img/install-extension.png) + +### Through the command line + +Just like Flarum, extensions are installed through [Composer](https://getcomposer.org), using SSH. To install a typical extension: + +1. `cd` to your Flarum directory. This directory should contain `composer.json`, `flarum` files and a `storage` directory (among others). You can check directory contents via `ls -la`. +2. Run `composer require COMPOSER_PACKAGE_NAME:*`. This should be provided by the extension's documentation. + +## Updating Extensions + +### Through the interface + +Using the extension manager extension, you can update extensions directly from the admin dashboard. You can run a check for updates by clicking the "Check for updates" button in the extension manager. If there are updates available, you can update all extensions by clicking the "Global update" button. Or, you can update individual extensions by clicking the "Update" button next to the extension you want to update. + +![Updating an extension](/en/img/update-extension.png) + +### Through the command line + +Follow the instructions provided by extension developers. If you're using `*` as the version string for extensions ([as is recommended](composer.md)), running the commands listed in the [Flarum upgrade guide](update.md) should update all your extensions. + +## Uninstalling Extensions + +### Through the interface + +Using the extension manager extension, you can uninstall extensions directly from the admin dashboard. You can uninstall an extension by clicking the "Uninstall" button next to the extension you want to uninstall inside the extension's page. + +![Uninstalling an extension](/en/img/uninstall-extension.png) + +### Through the command line + +Similarly to installation, to remove an extension: + +0. If you want to remove all database tables created by the extension, click the "Purge" button in the admin dashboard. See [below](#managing-extensions) for more information. +1. `cd` to your Flarum directory. +2. Run `composer remove COMPOSER_PACKAGE_NAME`. This should be provided by the extension's documentation. + +## Managing Extensions + +Each individual extension page of the admin dashboard provides a convenient way to manage the extension. You can: + +- Enable or disable the extension. +- See the settings provided by the extension, and change them. +- Revert an extension's migrations to remove any database modifications it made (this can be done with the Purge button). This will remove ALL data associated with the extension, and is irreversible. It should only be done when you're removing an extension, and don't plan to install it again. It is also entirely optional. +- See the extension's README, if it has one. +- See the extension's version. +- Uninstall the extension if the extension manager is installed. + +## Configuring additional extension repository sources + +The extension manager uses `composer` under the hood, and as such, it looks for extension packages in the same places as `composer`. By default, this is [Packagist](https://packagist.org/). However, you can configure additional sources for the extension manager to look for extensions in. This is useful if you want to install an extension that is not available on Packagist. + +In the admin page of the extension manager, clicking the **Add Repository** button will open a modal where you can enter the name and URL of the repository you want to add. The name is just a label for the repository, and can be anything you want. The URL should be the URL of the repository which depends on the type of repository you want to add. + +### Adding a repository from a VCS + +If you want to add a repository from a VCS (e.g. GitHub, GitLab, BitBucket, etc), the URL should be the URL of the repository's VCS. For example, if you had a private GitHub repository at `https://github.com/acme/flarum-extension`, you would enter that URL into the URL field. If it is a private source, you will need to enter an authentication method through the **New authentication method** button. The token can be generated from your VCS provider's website, and the host should be the domain of the VCS provider (e.g. `github.com`). + +### Adding a composer repository + +Extiverse provides access to premium extensions. It is a good example of a composer repository. You would specify the URL as `https://flarum.org/composer/` and the name as `premium`. You would also need to enter an authentication method through the **New authentication method** button. The token can be generated from your Flarum account's [subscriptions](https://flarum.org/dashboard/subscriptions) page with the Instructions button. + +* Type: `HTTP Bearer` +* Host: `flarum.org` + +![Configure repositories](/en/img/config-repositories.png) + +:::info + +The configured repositories and auth methods will be active for both the command line and the admin dashboard. If you configure them from the command line however, you must not include the flag `--global`. + +::: + +## Installing Non-stable extensions + +If for whatever reason you want to install a non-stable extension (e.g. a beta, alpha or RC version) you must first update the **Minimum stability** setting to the wanted stability. + +* If you set it to Alpha, you will be able to install alpha, beta, RC (Release Candidate) and stable versions. +* If you set it to Beta, you will be able to install beta, RC and stable versions. +* If you set it to RC, you will be able to install RC and stable versions. +* If you set it to Stable, you will only be able to install stable versions. diff --git a/versioned_docs/version-1.x/faq.md b/versioned_docs/version-1.x/faq.md new file mode 100644 index 000000000..d27e6bf91 --- /dev/null +++ b/versioned_docs/version-1.x/faq.md @@ -0,0 +1,35 @@ +# FAQ + +### Is Flarum Stable? + +Yes! After 6 years of development, Flarum 1.0.0 is finally here. + +### What's next after stable? + +We're still working on a formal roadmap. We have a lot of plans and ideas, and look forward to sharing a more thorough milestone with the community. + +### Can I donate money to speed up development? + +All donations are gratefully received. You can give on [GitHub Sponsors](https://github.com/sponsors/flarum) or [OpenCollective](https://opencollective.com/flarum). + +However, donations will not directly impact the speed of development on Flarum. We also encourage users to contribute in other ways, such as [contributing code](contributing.md), [building extensions](/extend/README.md), writing documentation, translating Flarum into other languages, providing help and support on the [community forums](https://discuss.flarum.org/)... and just being a general positive energy around the community! + +### Will Flarum have [insert feature here]? When? Why not? + +We would love to build countless features and extensions for Flarum, but first things first: Our focus is on the essentials and stability. + +### Why haven’t you fixed [insert issue here] yet? + +Here again, the answer is “first things first”. If we haven’t fixed an issue (or assigned it a milestone) yet, it’s because we’re working on something else that’s just as important. Please be patient; we’ll try to get it done before release. Or if you’re in a hurry, feel free to fix it yourself and [contribute to the project](contributing.md)! + +### Will I be able to migrate my forum to Flarum? + +We don't currently provide official migrators, but there are many community solutions out there. Relatively soon, we’ll start building tools to import data from other forum software like esoTalk, FluxBB, phpBB, Discourse, and others. + +### How do I join the Flarum team? + +> "Through an arcane and arduous ordeal, involving mystic rituals, life threatening peril, and adventures to far off lands where many go and few return." ~ jordanjay29 + +The real answer is that we generally keep an eye on our community for stand-out members who would make good staff. Honestly, for most of our current staff, what they did before becoming staff wasn't much different from what they do now. + +Find a passion and contribute however you feel is best. Then let it take its course. You don't have to have a badge to be respected here. \ No newline at end of file diff --git a/versioned_docs/version-1.x/install.md b/versioned_docs/version-1.x/install.md new file mode 100644 index 000000000..75f6e6001 --- /dev/null +++ b/versioned_docs/version-1.x/install.md @@ -0,0 +1,200 @@ +# Installation + +:::tip Quick test drive? + +Feel free to give Flarum a spin on one of our [demonstration forums](https://discuss.flarum.org/d/21101). Or set up your own forum in seconds at [Free Flarum](https://www.freeflarum.com), a free community service not affiliated with the Flarum team. + +::: + +## Server Requirements + +Before you install Flarum, it's important to check that your server meets the requirements. To run Flarum, you will need: + +* **Apache** (with mod\_rewrite enabled) or **Nginx** +* **PHP 7.3+** with the following extensions: curl, dom, fileinfo, gd, json, mbstring, openssl, pdo\_mysql, tokenizer, zip +* **MySQL 5.6+/8.0.23+** or **MariaDB 10.0.5+** +* **SSH (command-line) access** to run potentially necessary software maintenance commands, and Composer if you intend on using the command-line to install and manage Flarum extensions. + +## Installing + +### Installing by unpacking an archive + +If you don't have SSH access to your server or you prefer not to use the command line, you can install Flarum by unpacking an archive. Below is a list of the available archives, make sure you choose the one that matches your PHP version and public path or lack thereof preference. + +| Flarum Version | PHP Version | Public Path | Type | Archive | +|----------------|-------------------|-------------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------| +| 1.x | 8.3 (recommended) | No | ZIP | [flarum-v1.x-no-public-dir-php8.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.3.zip) | +| 1.x | 8.3 (recommended) | Yes | TAR.GZ | [flarum-v1.x-php8.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.3.tar.gz) | +| 1.x | 8.3 (recommended) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.3.tar.gz) | +| 1.x | 8.3 (recommended) | Yes | ZIP | [flarum-v1.x-php8.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.3.zip) | +| 1.x | 8.2 (recommended) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.2.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.2.tar.gz) | +| 1.x | 8.2 (recommended) | Yes | TAR.GZ | [flarum-v1.x-php8.2.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.2.tar.gz) | +| 1.x | 8.2 (recommended) | No | ZIP | [flarum-v1.x-no-public-dir-php8.2.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.2.zip) | +| 1.x | 8.2 (recommended) | Yes | ZIP | [flarum-v1.x-php8.2.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.2.zip) | +| 1.x | 8.1 | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.1.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.1.tar.gz) | +| 1.x | 8.1 | Yes | TAR.GZ | [flarum-v1.x-php8.1.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.1.tar.gz) | +| 1.x | 8.1 | No | ZIP | [flarum-v1.x-no-public-dir-php8.1.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.1.zip) | +| 1.x | 8.1 | Yes | ZIP | [flarum-v1.x-php8.1.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.1.zip) | +| 1.x | 8.0 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php8.0.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.0.tar.gz) | +| 1.x | 8.0 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php8.0.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.0.tar.gz) | +| 1.x | 8.0 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php8.0.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php8.0.zip) | +| 1.x | 8.0 (end of life) | Yes | ZIP | [flarum-v1.x-php8.0.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php8.0.zip) | +| 1.x | 7.4 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php7.4.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.4.tar.gz) | +| 1.x | 7.4 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php7.4.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.4.tar.gz) | +| 1.x | 7.4 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php7.4.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.4.zip) | +| 1.x | 7.4 (end of life) | Yes | ZIP | [flarum-v1.x-php7.4.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.4.zip) | +| 1.x | 7.3 (end of life) | No | TAR.GZ | [flarum-v1.x-no-public-dir-php7.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.3.tar.gz) | +| 1.x | 7.3 (end of life) | Yes | TAR.GZ | [flarum-v1.x-php7.3.tar.gz](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.3.tar.gz) | +| 1.x | 7.3 (end of life) | No | ZIP | [flarum-v1.x-no-public-dir-php7.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-no-public-dir-php7.3.zip) | +| 1.x | 7.3 (end of life) | Yes | ZIP | [flarum-v1.x-php7.3.zip](https://github.com/flarum/installation-packages/raw/main/packages/v1.x/flarum-v1.x-php7.3.zip) | + +### Installing using the Command Line Interface + +Flarum uses [Composer](https://getcomposer.org) to manage its dependencies and extensions. If you're not familiar with it, read [our guide](composer.md) for information on what it is and how to set it up. Afterwards, run this command in an empty location that you want Flarum to be installed in: + +```bash +composer create-project flarum/flarum . +``` + +While this command is running, you can configure your web server. You will need to make sure your webroot is set to `/path/to/your/forum/public`, and set up [URL Rewriting](#url-rewriting) as per the instructions below. + +When everything is ready, navigate to your forum in a web browser and follow the instructions to complete the installation. + +If you wish to install and update extensions from the admin dashboard, you need to also install the [Extension Manager](extensions.md) extension. + +```bash +composer require flarum/extension-manager:* +``` + +:::warning + +The extension manager allows an admin user to install any composer package. Only install the extension manager if you trust all of your forum admins with such permissions. + +::: + +## URL Rewriting + +### Apache + +Flarum includes a `.htaccess` file in the `public` directory – make sure it has been uploaded correctly. **Flarum will not function properly if `mod_rewrite` is not enabled or `.htaccess` is not allowed.** Be sure to check with your hosting provider (or your VPS) that these features are enabled. If you're managing your own server, you may need to add the following to your site configuration to enable `.htaccess` files: + +``` + + AllowOverride All + +``` + +This ensures that htaccess overrides are allowed so Flarum can rewrite URLs properly. + +Methods for enabling `mod_rewrite` vary depending on your OS. You can enable it by running `sudo a2enmod rewrite` on Ubuntu. `mod_rewrite` is enabled by default on CentOS. Don't forget to restart Apache after making modifications! + +### Nginx + +Flarum includes a `.nginx.conf` file – make sure it has been uploaded correctly. Then, assuming you have a PHP site set up within Nginx, add the following to your server's configuration block: + +```nginx +include /path/to/flarum/.nginx.conf; +``` + +### Caddy + +Caddy requires a very simple configuration in order for Flarum to work properly. Note that you should replace the URL with your own and the path with the path to your own `public` folder. If you are using a different version of PHP, you wil also need to change the `fastcgi` path to point to your correct PHP install socket or URL. + +``` +www.example.com { + root * /var/www/flarum/public + php_fastcgi unix//var/run/php/php7.4-fpm.sock + header /assets/* { + +Cache-Control "public, must-revalidate, proxy-revalidate" + +Cache-Control "max-age=25000" + Pragma "public" + } + file_server +} +``` +## Folder Ownership + +During installation, Flarum may request that you make certain directories writable. +Modern operating systems are generally multi-user, meaning that the user you log in as is not the same as the user Flarum is running as. +The user that Flarum is running as MUST have read + write access to: + +- The root install directory, so Flarum can edit `config.php`. +- The `storage` subdirectory, so Flarum can edit logs and store cached data. +- The `assets` subdirectory, so that logos and avatars can be uploaded to the filesystem. + +Extensions might require other directories, so you might want to recursively grant write access to the entire Flarum root install directory. + +There are several commands you'll need to run in order to set up file permissions. Please note that if your install doesn't show warnings after executing just some of these, you don't need to run the rest. + +First, you'll need to allow write access to the directory. On Linux: + +```bash +chmod 775 -R /path/to/directory +``` + +If that isn't enough, you may need to check that your files are owned by the correct group and user. By default, in most Linux distributions `www-data` is the group and user that both PHP and the web server operate under. You'll need to look into the specifics of your distro and web server setup to make sure. You can change the folder ownership in most Linux operating systems by running: + +```bash +chown -R www-data:www-data /path/to/directory +``` + +With `www-data` changed to something else if a different user/group is used for your web server. + +Additionally, you'll need to ensure that your CLI user (the one you're logged into the terminal as) has ownership, so that you can install extensions and manage the Flarum installation via CLI. To do this, add your current user (`whoami`) to the web server group (usually `www-data`) via `usermod -a -G www-data YOUR_USERNAME`. You will likely need to log out and back in for this change to take effect. + +Finally, if that doesn't work, you might need to configure [SELinux](https://www.redhat.com/en/topics/linux/what-is-selinux) to allow the web server to write to the directory. To do so, run: + +```bash +chcon -R -t httpd_sys_rw_content_t /path/to/directory +``` + +To find out more about these commands as well as file permissions and ownership on Linux, read [this tutorial](https://www.thegeekdiary.com/understanding-basic-file-permissions-and-ownership-in-linux/). If you are setting up Flarum on Windows, you may find the answers to [this Super User question](https://superuser.com/questions/106181/equivalent-of-chmod-to-change-file-permissions-in-windows) useful. + +:::caution Environments may vary + +Your environment may vary from the documentation provided, please consult your web server configuration or web hosting provider for the proper user and group that PHP and the web server operate under. + +::: + +:::danger Never use permission 777 + +You should never set any folder or file to permission level `777`, as this permission level allows anyone to access the content of the folder and file regardless of user or group. + +::: + +## Customizing Paths + +By default Flarum's directory structure includes a `public` directory which contains only publicly-accessible files. This is a security best-practice, ensuring that all sensitive source code files are completely inaccessible from the web root. + +However, if you wish to host Flarum in a subdirectory (like `yoursite.com/forum`), or if your host doesn't give you control over your webroot (you're stuck with something like `public_html` or `htdocs`), you can set up Flarum without the `public` directory. + +If you intend to install Flarum using one of the archives, you can simply use the `no-public-dir` (Public Path = No) [archives](#installing-by-unpacking-an-archive) and skip the rest of this section. If you're installing via Composer, you'll need to follow the instructions below. + +Simply move all the files inside the `public` directory (including `.htaccess`) into the directory you want to serve Flarum from. Then edit `.htaccess` and uncomment lines 9-15 in order to protect sensitive resources. For Nginx, uncomment lines 8-11 of `.nginx.conf`. + +You will also need to edit the `index.php` file and change the following line: + +```php +$site = require './site.php'; +``` + + Edit the `site.php` and update the paths in the following lines to reflect your new directory structure: + +```php +'base' => __DIR__, +'public' => __DIR__, +'storage' => __DIR__.'/storage', +``` + +Finally, check `config.php` and make sure the `url` value is correct. + +## Importing Data + +If you have an existing community and don't want to start from scratch, you may be able to import your existing data into Flarum. While there are no official importers yet, the community has made several unofficial importers: + +* [FluxBB](https://discuss.flarum.org/d/3867-fluxbb-to-flarum-migration-tool) +* [MyBB](https://discuss.flarum.org/d/5506-mybb-migrate-script) +* [phpBB](https://discuss.flarum.org/d/1117-phpbb-migrate-script-updated-for-beta-5) +* [SMF2](https://github.com/ItalianSpaceAstronauticsAssociation/smf2_to_flarum) + +These can be used for other forum software as well by migrating to phpBB first, then to Flarum. Be aware that we can't guarantee that these will work nor can we offer support for them. diff --git a/versioned_docs/version-1.x/internal/README.md b/versioned_docs/version-1.x/internal/README.md new file mode 100644 index 000000000..ff153a3bc --- /dev/null +++ b/versioned_docs/version-1.x/internal/README.md @@ -0,0 +1,7 @@ +--- +slug: '/internal' +--- + +# Internal Team Docs + +This is a new documentation section, where we will be posting some docs used internally by the Flarum team. We are starting this section to provide our community with transparency as to how Flarum is run, and to help those hoping to contribute to Flarum. \ No newline at end of file diff --git a/versioned_docs/version-1.x/internal/bundled-extensions-policy.md b/versioned_docs/version-1.x/internal/bundled-extensions-policy.md new file mode 100644 index 000000000..555e7977c --- /dev/null +++ b/versioned_docs/version-1.x/internal/bundled-extensions-policy.md @@ -0,0 +1,28 @@ +# Bundled Extensions Policy + +This document is to assist in deciding what core features should be bundled or maintained by the Flarum project team. + +Understand that Flarum aims to have a lean and efficient team. To guarantee a transparent workload, we intentionally have a "this could be an extension" mentality. The acronym D.O.R.C. spells out our decision-making process. + +- **Density**: prevent bloating Flarum so that it becomes a burden to install on shared hosting plans with limited space. +- **Opinionatedness**: no extensions should be bundled that is only useful by only a limited amount of communities or on specific hosting environments. +- **Responsibility**: extensions that could easily be maintained by others should be maintained by others. +- **Complexity**: extensions that are complex in terms of design, frontend or backend code should not be a responsibility of the Flarum project team. + +### Density + +To prevent the installation size of Flarum from continuously increasing we need to protect it from extensions that bloat it. We should ship extensions with Flarum that, for instance, have kilobytes in media files. + +### Opinionatedness + +Our goal is to allow installation of Flarum, in its vanilla form, by any community on any hosting environment. This includes shared hosting environment as well. + +Releasing Flarum with extensions that add functionality specific to cloud based (AWS) installations or for corporate support communities, as such, is unwanted. + +### Responsibility + +Protecting the time of the project team is key. To do so we should empower the ecosystem in building extensions that it needs. Therefor we distance ourselves from the responsibility of building every and all extensions. The responsibility of extension development is held primarily by our community. + +### Complexity + +Complex extensions require a vast amount of time, not just for development, but also documentation and support. To protect the lean and efficient principles of the team, we will not take ownership of extensions that add this complexity. diff --git a/versioned_docs/version-1.x/internal/extension-manager.md b/versioned_docs/version-1.x/internal/extension-manager.md new file mode 100644 index 000000000..de9ee751f --- /dev/null +++ b/versioned_docs/version-1.x/internal/extension-manager.md @@ -0,0 +1,88 @@ +# Extension Manager +This contains an explanation of how the extension manager works and what it has to offer. + +slightly outdated: see [the extensions guide for more](/extensions.md). + +## Contents +* Installing, Updating, and Removing Extensions. +* [Checking for Updates](#checking-for-updates). +* [Global Flarum Update](#global-flarum-updates). +* [Patch-Minor Flarum Updates](#patch-minor-flarum-updates). +* [Major Flarum Update](#major-flarum-updates). +* [Flarum Updates (global, minor, major)](#flarum-updates-global-minor-major). +* [Background Tasks](#background-tasks). + +## Requirements +There are some obstacles that need to be taken care of before this can be used. + +### File Permissions +The relevant machine web user needs to have permissions to read and write to: `vendor`, `composer.json`, `composer.lock` and `storage`. Right now a warning shows up when this is not the case, this should preferably be changed to mention only the files/dirs where permissions are lacking instead of all of them. + +![flarum lan_admin (3)](https://user-images.githubusercontent.com/20267363/135268536-f79d42ab-6e05-4e41-b2ab-d95ec7a8b021.png) + +### Path Repository +In development environments (and production in rare scenarios) there should a path repository to a directory containing (mostly dev) packages, the path to this directory must be changed to an absolute path otherwise composer will have trouble running any command. Additionally the path repository by default has higher priority, so requiring an extension that exists in that repository will probably fail, unless a `*@dev` constraint is specified, in which case the extension manager should not be used for dev purposes anyway. + +There is currently now hint of any of this in the extension manager UI. + +## Common Actions +Each one of the features listed above is basically a composer command or two, and there are common actions/common behaviour between them all. + +* Restricting access to the admin. +* Validating the provided package name or the extension id if given. +* Erroring out if installing an existing extension, updating or removing a non existing extension ...etc +* Running the command. This [auto logs the output](#command-output-logging). +* [Erroring out on command failure](#command-failure). +* Dispatching an event. +* If running an update: + + Clear Cache. + + Run Migrations. + + Publish Assets. + + Run an update check, and log any extensions that didn't update to their latest versions in the update process. + +### Command Output Logging +Considering this is still experimental and especially for the sake of easier support, each command output is logged to `storage/logs/composer` just like the flarum error logs, allowing to go back and see what happened during a command execution. + +### Command Failure +When a composer command fails (recognised by the exit code), an exception is thrown containing a reason guessed by the exception based on the command output text. Guessed causes render into proper explanatory alert messages on the frontend. + +## Checking for Updates +This executes the command `composer outdated -D --format json` which checks for updates of packages directly required in the root `composer.json` and outputs the results in JSON format. Only packages marked as `semver-safe-update` and `update-possible` by composer are displayed. + +The information about the last update check is saved into a JSON setting. + +![flarum lan_admin (4)](https://user-images.githubusercontent.com/20267363/135272032-9de37599-b364-4e42-b234-1113135eaa83.png) + +## Global Flarum Updates +Simply runs the command `command update --prefer-dist --no-dev -a --with-all-dependencies`, useful for updating all packages. + +## Patch-Minor Flarum Updates +This changes directly required package versions to `*` and then executes the command `command update --prefer-dist --no-dev -a --with-all-dependencies`. + +![flarum lan_admin (5)](https://user-images.githubusercontent.com/20267363/135276114-ae438c2f-4122-45bd-b32f-690de3b56e25.png) + +## Major Flarum Updates +This changes directly required package versions to `*`, changes core to the latest major version requirement and then executes the same command above. Upon failure, it can be correctly guessed that some extensions are not compatible with the new major version, the exception details will include an array of extension package names that are not compatible, and it'll be rendered in the frontend, with the ability to run a `composer why-not flarum/core 2.0` for more details. + +![major update UI](https://user-images.githubusercontent.com/20267363/143277865-8323fa9a-c80f-4015-baca-fce4d2b5d585.png) + +## Flarum Updates (global, minor, major) +Information about the last updates ran are saved in a `last_update_run` JSON setting, which can contain an array of extension package names that didn't update to their latest version in the process, this is rendered in the frontend as warning icon buttons on the extension items, clicking on them will execute a `composer why-not`, displaying the details of the failure in a modal. + +![UI with list of extensions containing warning icon buttons](https://user-images.githubusercontent.com/20267363/143278774-6fada0da-dead-474b-8dfa-feda5021134f.png) +![UI with the modal showing the details](https://user-images.githubusercontent.com/20267363/143278786-d283db62-de96-4019-954e-932d0d6eac15.png) + +## Background Tasks +To get around timeout issues, composer commands can also run on the background use the queue. Users can be pointed towards [Blomstra's Database Queue Implementation](https://discuss.flarum.org/d/28151-database-queue-the-simplest-queue-even-for-shared-hosting) as a basic queue solution. It contains instructions on how to enable the queue through a cron job. + +:::danger Cron Job PHP Process Version + +It is common for shared hosts to have a low php version used in SSH, users must be pointed to the fact that they have to make sure the php process is of a version compatible with Flarum. Either by manually checking or by asking their hosts. + +::: + +![Extension Manager Queue Table Preview](/en/img/extension-manager-queue.png) + +## TODO +- Try on shared hosting. +- Better explanation on the UI about background tasks. diff --git a/versioned_docs/version-1.x/internal/merging-policy.md b/versioned_docs/version-1.x/internal/merging-policy.md new file mode 100644 index 000000000..067e2809f --- /dev/null +++ b/versioned_docs/version-1.x/internal/merging-policy.md @@ -0,0 +1,38 @@ +# PR Merging Policy + +Technical contributions to the Flarum source code go through a review process. Over the years we have tuned this process based on our experiences, our targeted development speed and availability. + +## What makes a great Pull Request? + +Great pull requests: + +- Have the [Pull Request template](https://github.com/flarum/.github/blob/main/PULL_REQUEST_TEMPLATE.md) filled out completely when opening a pull request. +- Do not combine different changes. Although tempting, don't change formatting of unrelated code. Stick to the one feature or change you wish to contribute. +- Have a related issue where the technical implementation has been agreed upon by the core team, or has been approved on by the core team through discussion on the official forums or other channels like Discord. +- Clearly explain the need for the change and list the areas where the pull request requires discussion. + +## Implementation Review Criteria + +- Adheres to our conventions or can be patched up easily after merging, follows proper code style. +- Are there any implementation details that could be done better through alternate technologies/technical approaches? +- Does not touch any lines outside of the intended changes, eg through formatting or compilation. +- If the changes are to code intended as a public API, has a proper doc block been included? + +## Merge Time! + +If all the checks in the template are met, **any** core developer may merge this PR. If the PR is authored by a core developer, they should probably be the ones to merge it. + +- Merging: + - GitHub offers several ways to merge a PR. Choose between the following strategies: + - **Merge** when the PR branch consists of atomic, well-described commits that are nice to have in the version history. + - **Squash** when lots of cleanup commits have accumulated. Please make sure to follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) spec for the squash commit. We usually find several commits from bots like StyleCI in these prefabricated commit messages, their commit messages should be removed. + +- After merging: + - Assign the related issue (if none exists, the pull request itself, but never both) to the appropriate milestone. + - Close all relevant issues (*if* they are closed completely). + - Regressions should be labeled as such and removed from the project board and milestone after merging. + - Check for follow-up tasks: + - Merge related PRs (language files, extensions, documentations). + - Documentation updates. + - Create issues for further follow-up tasks, if necessary. + diff --git a/versioned_docs/version-1.x/languages.md b/versioned_docs/version-1.x/languages.md new file mode 100644 index 000000000..e89746c5e --- /dev/null +++ b/versioned_docs/version-1.x/languages.md @@ -0,0 +1,30 @@ +# Languages + +It’s easy to add a new language to your basic Flarum installation. Just follow the instructions below to download and install the language pack of your choice. + +Once you have added a language pack, you can [set it as the default language](#setting-the-default-language) for your forum. And if you ever find you don’t need one of your installed language packs, you can always [disable it](#disabling-a-language-pack). +If you’re using any third-party extensions, be sure to [read this](#third-party-extensions) before you start. + +## Language Pack Installation + +To begin, visit the [Extensions > Languages](https://discuss.flarum.org/t/languages) tag at the Flarum Community site and find a language pack that you want to install. + +Language packs are installed the same way as [extensions](extensions.md). The language will appear in the **Extensions** page of the admin interface and you can enable it there. + +That’s all there is to it! You should now be able to use the language selector in your site’s header to switch your forum’s display to the new language. + +## Setting the Default Language + +Once you have installed a language pack and made sure it’s working, you may want to set it as the default language for new users and guests. You can do that on the **Basics** page of the admin interface. + +## Disabling a Language Pack + +If you decide you don’t need to support a certain language, after all, you can turn it off. Simply locate the language pack in the **Extensions** page of the admin interface and disable it. + +Disabling a language can be useful if you’re running a monolingual site and don’t want the language selector to appear in the site header. The language selector is hidden when only one language is enabled. + +## Community Extensions + +While language packs downloaded from the Flarum Community site will generally include translations for all the extensions that come bundled with Flarum, they _will not_ as a rule cover any community extensions you may have installed. It is up to developers to provide and maintain translations for their extensions. + +So before you install a community extension, you should check to make sure it includes translations for each language pack you have installed. If you find that an extension doesn’t support a language you need, please contact the developer directly and arrange to have the necessary translations added. diff --git a/versioned_docs/version-1.x/mail.md b/versioned_docs/version-1.x/mail.md new file mode 100644 index 000000000..3f354df6f --- /dev/null +++ b/versioned_docs/version-1.x/mail.md @@ -0,0 +1,29 @@ +# Email Configuration + +Any community needs to send emails to allow for email verification, password resets, notifications, and other communication to users. Configuring your forum to send emails should be one of your first steps as an admin: an incorrect configuration will cause errors when users try to register. + +## Available Drivers + +Flarum provides several drivers by default, they are listed and explained below. Developers can also add [custom mail drivers through extensions](extend/mail.md). + +### SMTP + +This is probably the most commonly used email driver, allowing you to configure a host, port/encryption, username, and password for an external SMTP service. Please note that the encryption field expects either `ssl` or `tls`. + +### Mail + +The `mail` driver will try to use the sendmail / postfix email system included in many hosting servers. You must properly install and configure sendmail on your server for this to work. + +### Mailgun + +This driver uses your [Mailgun](https://www.mailgun.com/) account to send emails. You'll need a secret key, as well as the domain and region from your mailgun configuration. + +To use the mailgun driver, you'll need to install the Guzzle composer package (a PHP HTTP client). You can do this by running `composer require guzzlehttp/guzzle:^6.0|^7.0` in your Flarum install's root directory. + +### Log + +The log mail driver DOES NOT SEND MAIL, and is primarily used by developers. It writes the content of any emails to the log file in `FLARUM_ROOT_DIRECTORY/storage/logs`. + +## Testing Email + +Once you've saved an email configuration, you can click the "Send Test Mail" button on the Mail page of the admin dashboard to make sure your configuration works. If you see an error, or do not receive an email, adjust the configuration and try again. Make sure to check your spam if there's no error, but nothing shows up in your inbox. diff --git a/versioned_docs/version-1.x/releases.md b/versioned_docs/version-1.x/releases.md new file mode 100644 index 000000000..237a70bc7 --- /dev/null +++ b/versioned_docs/version-1.x/releases.md @@ -0,0 +1,14 @@ +# Release Notes + + + +Release notes can be found in the [Flarum Community](https://discuss.flarum.org/t/blog?sort=newest). diff --git a/versioned_docs/version-1.x/rest-api.md b/versioned_docs/version-1.x/rest-api.md new file mode 100644 index 000000000..9ede50b63 --- /dev/null +++ b/versioned_docs/version-1.x/rest-api.md @@ -0,0 +1,389 @@ +# Consuming the REST API + +Flarum exposes a REST API which is used by the single page application but also available for external scripts. + +The API follows the best practices defined by the [JSON:API](https://jsonapi.org/) specification. + +:::info + +To extend the REST API with new endpoints, see [API and Data Flow](extend/api.md) in the developer documentation. + +::: + +## Authentication + +The single page app uses session cookies to authenticate against the API. +External scripts can use stateless authentication using [API Keys](#api-keys) or [Access Tokens](#access-tokens). + +`GET` endpoints can be used without authentication. +Only content visible to guests will be returned. +Other endpoints generally cannot be used without authentication because of the [CSRF protection](#csrf-protection). + +### API keys + +API Keys are the primary way for scripts, tools and integrations to interact with Flarum. + +#### Creation + +There is currently no UI to manage API Keys, but they can be created manually in the `api_keys` table of the database. + +The following attributes can be filled: + +- `key`: Generate a long unique token (recommended: alpha-numerical, 40 characters) and set it here, this will be the token used in the `Authorization` header. +- `user_id`: Optional. If set, the key can only be used to act as the given user. + +The remaining attributes are either automatically filled or currently not used: + +- `id`: Will be filled by MySQL auto-increment. +- `allowed_ips`: Not implemented. +- `scopes`: Not implemented. +- `created_at`: Can be set to any date, but is meant for the date of creation of the key. +- `last_activity_at`: Will be updated automatically when the token is used. + +#### Usage + +Attach your key value to each API request using the `Authorization` header. +Then provide the user ID you want to interact as at the end of the header: + + Authorization: Token YOUR_API_KEY_VALUE; userId=1 + +If a `user_id` value has been set for the key in the database, `userId=` will be ignored. +Otherwise, it can be set to any valid user ID that exists in the database. + +### Access Tokens + +Access Tokens are short-lived tokens that belong to a specific user. + +Those tokens are used behind the scenes for cookie sessions. +Their use in stateless API requests has the same effect as a regular session. +The user last activity will be updated each time the token is used. + +#### Creation + +All users are allowed to create access tokens. +To create a token, use the `/api/token` endpoint with the credentials of your user: + +``` +POST /api/token HTTP/1.1 + +{ + "identification": "Toby", + "password": "pass7word" +} + +HTTP/1.1 200 OK + +{ + "token": "YACub2KLfe8mfmHPcUKtt6t2SMJOGPXnZbqhc3nX", + "userId": "1" +} +``` + +At the moment, 3 token types exist, although only 2 types can be created via the REST API. + +- `session` tokens expire after 1h of inactivity. This is the default token type. +- `session_remember` tokens expire after 5 years of inactivity. They can be obtained by specifying `remember=1` in the request attributes. +- `developer` tokens never expire. They can only be created manually in the database at the moment. + +**All access tokens are deleted when the user logs out** (this includes `developer` tokens, although it is planned to change it). + +#### Usage + +Attach the returned `token` value to each API request using the `Authorization` header: + + Authorization: Token YACub2KLfe8mfmHPcUKtt6t2SMJOGPXnZbqhc3nX + +### CSRF Protection + +Most of the `POST`/`PUT`/`DELETE` API endpoints are protected against [Cross-site request forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery). +This means stateless requests are not possible without authentication. + +When using an API Key or Access Token, CSRF protection is bypassed. + +## Endpoints + +This part of the documentation is still in progress. +We are researching options to provide an automated documentation of the endpoints. + +Every extension adds new endpoints and attributes so it's difficult to provide a complete documentation of all endpoints. +A good way to discover endpoints is to use the browser development tools to inspect requests made by the single page application. + +Below are a few examples of commonly used endpoints. +JSON has been truncated to make reading easier. + +### List discussions + + GET /api/discussions + +```json +{ + "links": { + "first": "https://flarum.tld/api/discussions", + "next": "https://flarum.tld/api/discussions?page%5Boffset%5D=20" + }, + "data": [ + { + "type": "discussions", + "id": "234", + "attributes": { + "title": "Lorem Ipsum", + "slug": "234-lorem-ipsum", + "commentCount": 10, + "participantCount": 3, + "createdAt": "2022-01-01T10:20:30+00:00", + "lastPostedAt": "2022-01-05T10:20:30+00:00", + "lastPostNumber": 10, + "canReply": true, + "canRename": true, + "canDelete": true, + "canHide": true, + "isHidden": true, + "hiddenAt": "2022-01-06T10:20:30+00:00", + "lastReadAt": "2022-01-02T10:20:30+00:00", + "lastReadPostNumber": 2, + "isApproved": true, + "canTag": true, + "isLocked": false, + "canLock": true, + "isSticky": false, + "canSticky": true, + "canMerge": true, + "subscription": null + }, + "relationships": { + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + "lastPostedUser": { + "data": { + "type": "users", + "id": "64" + } + }, + "tags": { + "data": [ + { + "type": "tags", + "id": "3" + } + ] + }, + "firstPost": { + "data": { + "type": "posts", + "id": "668" + } + } + } + }, + { + "type": "discussions", + "id": "234", + "attributes": { + // [...] + }, + "relationships": { + // [...] + } + }, + // [...] more discussions + ], + "included": [ + { + "type": "users", + "id": "1", + "attributes": { + "username": "Admin", + "displayName": "Admin", + "avatarUrl": null, + "slug": "1" + } + }, + { + "type": "users", + "id": "64", + "attributes": { + "username": "Flarum", + "displayName": "Flarum", + "avatarUrl": "https://flarum.tld/assets/avatars/Z4hEncw0ndVqZ8be.png", + "slug": "64" + } + }, + { + "type": "tags", + "id": "3", + "attributes": { + "name": "Welcome", + "description": "Post interesting things here", + "slug": "welcome", + "color": "#888", + "backgroundUrl": null, + "backgroundMode": null, + "icon": "fas fa-bullhorn", + "discussionCount": 30, + "position": 1, + "defaultSort": null, + "isChild": false, + "isHidden": false, + "lastPostedAt": "2022-01-05T10:20:30+00:00", + "canStartDiscussion": true, + "canAddToDiscussion": true, + "isRestricted": false + } + }, + { + "type": "posts", + "id": "668", + "attributes": { + "number": 1, + "createdAt": "2022-01-01T10:20:30+00:00", + "contentType": "comment", + "contentHtml": "

Hello World

" + } + }, + // [...] more includes for the other discussions + ] +} +``` + +### Create discussion + + POST /api/discussions + +```json +{ + "data":{ + "type": "discussions", + "attributes": { + "title": "Lorem Ipsum", + "content": "Hello World" + }, + "relationships": { + "tags": { + "data": [ + { + "type": "tags", + "id": "1" + } + ] + } + } + } +} +``` + +The response includes the ID of the new discussion: + +```json +{ + "data": { + "type": "discussions", + "id": "42", + "attributes": { + "title": "Lorem Ipsum", + "slug": "42-lorem-ipsum", + "commentCount": 1 + // [...] other attributes + }, + "relationships": { + "posts": { + "data": [ + { + "type": "posts", + "id": "58" + } + ] + }, + "user": { + "data": { + "type": "users", + "id": "1" + } + }, + // [...] other relationships + } + }, + "included":[ + { + "type": "posts", + "id": "38", + "attributes": { + "number": 1, + "contentType": "comment", + "contentHtml": "\u003Cp\u003EHello World\u003C\/p\u003E" + // [...] other attributes + } + } + // [...] other includes + ] +} +``` + +### Create user + + POST /api/users + +```json +{ + "data": { + "attributes": { + "username": "Flarum", + "email": "flarum@example.com", + "password": "correcthorsebatterystaple" + } + } +} +``` + +## Errors + +Flarum uses various HTTP status code and includes error descriptions that follow the [JSON:API error spec](https://jsonapi.org/format/#errors). + +Below are a few common errors you might encounter when using the REST API: + +### CSRF Token Mismatch + +If you receive a 400 HTTP error with `csrf_token_mismatch` message, it means the `Authorization` header is absent or invalid and Flarum attempted to authenticate through the session cookie. + +```json +{ + "errors": [ + { + "status": "400", + "code": "csrf_token_mismatch" + } + ] +} +``` + +### Validation errors + +Validation errors are returned with 422 HTTP status code. +The name of the invalid field is returned as the `pointer` value. +There can be multiple errors for a single field at the same time. + +```json +{ + "errors": [ + { + "status": "422", + "code": "validation_error", + "detail": "The username has already been taken.", + "source":{ + "pointer":"\/data\/attributes\/username" + } + }, + { + "status": "422", + "code": "validation_error", + "detail": "The email has already been taken.", + "source": { + "pointer":"\/data\/attributes\/email" + } + } + ] +} +``` diff --git a/versioned_docs/version-1.x/scheduler.md b/versioned_docs/version-1.x/scheduler.md new file mode 100644 index 000000000..6123ce7c3 --- /dev/null +++ b/versioned_docs/version-1.x/scheduler.md @@ -0,0 +1,55 @@ +# Scheduler + +The Flarum scheduler allows extensions to automate certain tasks effortlessly. In this guide we will see how to set it up. We won't go into the details of cron itself, but if you want to read more about it, I suggest you take a look at [this Wikipedia article](https://en.wikipedia.org/wiki/Cron) on cron. + +## Why should I care? + +Quite simply, a growing list of extensions now support handling certain functions automatically for you, completely behind the scenes. Wondering why `fof/drafts` 'scheduled drafts' are not posting, or `fof/best-answer` 'remind users to set a best answer after X days' does not fire? That'll be because they will setup themselves with the scheduler service, but without a one-liner cron job, nothing will happen! + +## What extensions currently use the scheduler? + +Some of the most popular examples are the following: + +- [FoF Best Answer](https://github.com/FriendsOfFlarum/best-answer) +- [FoF Drafts](https://github.com/FriendsOfFlarum/drafts) +- [FoF Sitemap](https://github.com/FriendsOfFlarum/sitemap) +- [FoF Open Collective](https://github.com/FriendsOfFlarum/open-collective) +- [FoF Github Sponsors](https://github.com/FriendsOfFlarum/github-sponsors) + +## Ok, let's get this setup! + +Most (if not all) Linux distros either come with, or can have, cron installed. For example, on Debian and Ubuntu based systems, you can install `cron` like this: + +``` +sudo apt-get update +sudo apt-get install cron +``` + +In case you are using a RHEL based Linux distribution (CentOS, AlmaLinux, Rocky Linux...), install cron like this: + +``` +sudo dnf update +sudo dnf install crontabs +``` + +Once you have cron installed, let's create the one and only entry you need for Flarum: + +``` +crontab -e +``` + +This will open the cron editor. You may or may not have other entries there. Add this line, and remember to leave an empty line at the bottom. + +``` +* * * * * cd /path-to-your-project && php flarum schedule:run >> /dev/null 2>&1 +``` + +`* * * * *` tells cron to run your command every minute. + +In case you want to use a different value and don't know exactly how cron expressions work, you can use a [cron expression generator](https://crontab.guru) to easily get the desired string. + +`cd /path-to-your-project && php flarum schedule:run` executes Flarum's scheduler to trigger any tasks currently waiting to be run. If PHP isn't in your system's path, you may need to experiment with setting the full path to PHP. + +Lastly `>> /dev/null 2>&1` suppresses any output from the command. + +Voila! Now any extension that registers a task to run, anything from every minute to daily, monthly, yearly - whatever - will now run on your server. diff --git a/versioned_docs/version-1.x/themes.md b/versioned_docs/version-1.x/themes.md new file mode 100644 index 000000000..ba0e46541 --- /dev/null +++ b/versioned_docs/version-1.x/themes.md @@ -0,0 +1,33 @@ +# Theming + +While we've worked hard to make Flarum as beautiful as we can, each community will probably want to make some tweaks/modifications to fit their desired style. + +## Admin Dashboard + +The [admin dashboard](admin.md)'s Appearance page is a great first place to start customizing your forum. Here, you can: + +- Select theme colors +- Toggle dark mode and a colored header +- Upload a logo and favicon (icon shown in browser tabs) +- Add HTML for custom headers and footers +- Add [custom LESS/CSS](#css-theming) to change how elements are displayed + +## CSS Theming + +CSS is a style sheet language that tells browsers how to display elements of a webpage. +It allows us to modify everything from colors to fonts to element size and positioning to animations. +Adding custom CSS can be a great way to modify your Flarum installation to match a theme. + +A CSS tutorial is beyond the scope of this documentation, but there are plenty of great online resources to learn the basics of CSS. + +:::tip + +Flarum actually uses LESS, which makes it easier to write CSS by allowing for variables, conditionals, and functions. + +::: + +## Extensions + +Flarum's flexible [extension system](extensions.md) allows you to add, remove, or modify practically any part of Flarum. +If you want to make substantial theming modifications beyond changing colors/sizes/styles, a custom extension is definitely the way to go. +To learn how to make an extension, check out our [extension documentation](extend/README.md)! diff --git a/versioned_docs/version-1.x/troubleshoot.md b/versioned_docs/version-1.x/troubleshoot.md new file mode 100644 index 000000000..7bae80216 --- /dev/null +++ b/versioned_docs/version-1.x/troubleshoot.md @@ -0,0 +1,57 @@ +# Troubleshooting + +If Flarum isn't installing or working as expected, the first thing you should do is *check again* whether your environment meets the [system requirements](install.md#server-requirements). If you're missing something that Flarum needs to run, you'll need to remedy that first. + +Next, you should take a few minutes to search the [Support forum](https://discuss.flarum.org/t/support) and the [issue tracker](https://github.com/flarum/core/issues). It's possible that someone has already reported the problem, and a fix is either available or on the way. If you've searched thoroughly and can't find any information about the problem, it's time to start troubleshooting. + +## Step 0: Activate debug mode + +:::danger Skip on Production + +These debugging tools are very useful, but can expose information that shouldn't be public. +These are fine if you're on a staging or development environment, but if you don't know what you're doing, skip this step when on a production environment. + +::: + +Before you proceed, you should enable Flarum's debugging tools. Simply open up **config.php** with a text editor, change the `debug` value to `true`, and save the file. This will cause Flarum to display detailed error messages, giving you an insight into what's going wrong. + +If you've been seeing blank pages and the above change doesn't help, try setting `display_errors` to `On` in your **php.ini** configuration file. + +## Step 1: Common Fixes + +A lot of issues can be fixed with the following: + +* Clear your browser cache +* Clear the backend cache with [`php flarum cache:clear`](console.md). +* Make sure your database is updated with [`php flarum migrate`](console.md). +* Ensure that the [email configuration](mail.md) in your admin dashboard is correct: invalid email config will cause errors when registering, resetting a password, changing emails, and sending notifications. +* Check that your `config.php` is correct. For instance, make sure that the right `url` is being used (`https` vs `http` and case sensitivity matter here!). +* One potential culprit could be a custom header, custom footer, or custom LESS. If your issue is in the frontend, try temporarily removing those via the Appearance page of the admin dashboard. + +You'll also want to take a look at the output of [`php flarum info`](console.md) to ensure that nothing major is out of place. + +## Step 2: Reproduce the issue + +Try to make the problem happen again. Pay careful attention to what you're doing when it occurs. Does it happen every time, or only now and then? Try changing a setting that you think might affect the problem, or the order in which you're doing things. Does it happen under some conditions, but not others? + +If you've recently added or updated an extension, you should disable it temporarily to see if that makes the problem go away. Make sure all of your extensions were meant to be used with the version of Flarum you're running. Outdated extensions can cause a variety of issues. + +Somewhere along the way you may get an idea about what's causing your issue, and figure out a way to fix it. But even if that doesn't happen, you will probably run across a few valuable clues that will help us figure out what's going on, once you've filed your bug report. + +## Step 3: Collect information + +If it looks like you're going to need help solving the problem, it's time to get serious about collecting data. Look for error messages or other information about the problem in the following places: + +* Displayed on the actual page +* Displayed in the browser console (Chrome: More tools -> Developer Tools -> Console) +* Recorded in the server's error log (e.g. `/var/log/nginx/error.log`) +* Recorded in PHP-FPM's error log (e.g. `/var/log/php7.x-fpm.log`) +* Recorded by Flarum (`storage/logs`) + +Copy any messages to a text file and jot down a few notes about *when* the error occurred, *what* you were doing at the time, and so on. Be sure to include any insights you may have gleaned about the conditions under which the issue does and doesn't occur. Add as much information as possible about your server environment: OS version, web server version, PHP version and handler, et cetera. + +## Step 4: Prepare a report + +Once you have gathered all the information you can about the problem, you're ready to file a bug report. Please follow the instructions on [Reporting Bugs](bugs.md). + +If you discover something new about the issue after filing your report, please add that information at the bottom of your original post. It's a good idea to file a report even if you have solved the problem on your own, since other users may also benefit from your solution. If you've found a temporary workaround for the problem, be sure to mention that as well. \ No newline at end of file diff --git a/versioned_docs/version-1.x/update.md b/versioned_docs/version-1.x/update.md new file mode 100644 index 000000000..21b090eb2 --- /dev/null +++ b/versioned_docs/version-1.x/update.md @@ -0,0 +1,110 @@ +# Updating + +## From the Admin Dashboard + +:::info + +If you have the extension manager extension installed you can simply run the update from its interface and skip this page entirely. + +::: + +--- + +To update Flarum, you'll need to use [Composer](https://getcomposer.org). If you're not familiar with it (although you should be, because you need it to install Flarum), read [our guide](composer.md) for information on what it is and how to set it up. + +If updating across major versions (e.g. <=0.1.0 to 1.x.x, 1.x.x to 2.x.x, ...), make sure to read the appropriate "major version update guide" before running the general upgrade steps. + +## General Steps + +**Step 1:** Make sure all your extensions have versions compatible with the Flarum version you're trying to install. This is only needed across major versions (e.g. you probably don't need to check this if upgrading from v1.0.0 to v1.1.0, assuming your extensions follow recommended versioning). You can check this by looking at the extension's [Discuss thread](https://discuss.flarum.org/t/extensions), searching for it on [Packagist](http://packagist.org/), or checking databases like [Extiverse](https://extiverse.com). You'll need to remove (not just disable) any incompatible extensions before updating. Please be patient with extension developers! + +**Step 2:** Take a look at your `composer.json` file. Unless you have a reason to require specific versions of extensions or libraries, you should set the version string of everything except `flarum/core` to `*` (including `flarum/tags`, `flarum/mentions`, and other bundled extensions). Make sure `flarum/core` is NOT set to `*`. If you're targeting a specific version of Flarum, set `flarum/core` to that (e.g. `"flarum/core": "v0.1.0-beta.16`). If you just want the most recent version, use `"flarum/core": "^1.0"`. + +**Step 3:** If your local install uses [local extenders](extenders.md), make sure they are up to date with changes in Flarum. + +**Step 4:** We recommend disabling third-party extensions in the admin dashboard before updating. This isn't strictly required, but will make debugging easier if you run into issues. + +**Step 5:** Make sure your PHP version is supported by the version of Flarum you are trying to upgrade to, and that you are using Composer 2 (`composer --version)`. + +**Step 6:** Finally, to update, run: + +``` +composer update --prefer-dist --no-plugins --no-dev -a --with-all-dependencies +php flarum migrate +php flarum cache:clear +``` + +**Step 7:** If applicable, restart your PHP process and opcache. + +## Major Version Update Guides + +### Updating from Beta (<=0.1.0) to Stable v1 (^1.0.0) + +1. Do steps 1-5 above. +2. Change the version strings of all bundled extensions (`flarum/tags`, `flarum/mentions`, `flarum/likes`, etc) in `composer.json` from `^0.1.0` to `*`. +3. Change `flarum/core`'s version string in `composer.json` from `^0.1.0` to `^1.0`. +4. Remove the `"minimum-stability": "beta",` line from your `composer.json` +5. Do steps 6 and 7 above. + +## Troubleshooting Issues + +There are 2 main places where you might run into errors when updating Flarum: while running the update command itself, or when accessing the forum after updating. + +### Errors While Updating + +Here we'll go through several common types of issues while trying to update Flarum. + +--- + +If the output is short and contains: + +``` +Nothing to modify in lock file +``` + +Or does not list `flarum/core` as an updated package, and you are not on the latest flarum version: + +- Revisit step 2 above, make sure that all third party extensions have an asterisk for their version string. +- Make sure your `flarum/core` version requirement isn't locked to a specific minor version (e.g. `v0.1.0-beta.16` is locked, `^1.0.0` isn't). If you're trying to update across major versions of Flarum, follow the related major version update guide above. + +--- + +For other errors, try running `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO` + +If the output looks something like this: + +``` +flarum/flarum - requires flarum/core (v0.1.0-beta.15) +fof/moderator-notes 0.4.4 requires flarum/core (>=0.1.0-beta.15 <0.1.0-beta.16) +jordanjay29/flarum-ext-summaries 0.3.2 requires flarum/core (>=0.1.0-beta.14 <0.1.0-beta.16) +flarum/core v0.1.0-beta.16 requires dflydev/fig-cookies (^3.0.0) +flarum/flarum - does not require dflydev/fig-cookies (but v2.0.3 is installed) +flarum/core v0.1.0-beta.16 requires franzl/whoops-middleware (^2.0.0) +flarum/flarum - does not require franzl/whoops-middleware (but 0.4.1 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/bus (^8.0) +flarum/flarum - does not require illuminate/bus (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/cache (^8.0) +flarum/flarum - does not require illuminate/cache (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/config (^8.0) +flarum/flarum - does not require illuminate/config (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/container (^8.0) +flarum/flarum - does not require illuminate/container (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/contracts (^8.0) +flarum/flarum - does not require illuminate/contracts (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/database (^8.0) +flarum/flarum - does not require illuminate/database (but v6.20.19 is installed) +flarum/core v0.1.0-beta.16 requires illuminate/events (^8.0) +flarum/flarum - does not require illuminate/events (but v6.20.19 is installed) +... (this'll go on for a bit) +``` + +It is very likely that some of your extensions have not yet been updated. + +- Revisit step 1 again, make sure all your extensions have versions compatible with the core version you want to upgrade to. Remove any that don't. +- Make sure you're running `composer update` with all the flags specified in the update step. + +If none of this fixes your issue, feel free to reach out on our [Support forum](https://discuss.flarum.org/t/support). Make sure to include the output of `php flarum info` and `composer why-not flarum/core VERSION_YOU_WANT_TO_UPGRADE_TO`. + +### Errors After Updating + +If you are unable to access your forum after updating, follow our [troubleshooting instructions](troubleshoot.md). diff --git a/versioned_sidebars/version-1.x-sidebars.json b/versioned_sidebars/version-1.x-sidebars.json new file mode 100644 index 000000000..c8edad68f --- /dev/null +++ b/versioned_sidebars/version-1.x-sidebars.json @@ -0,0 +1,155 @@ +{ + "guideSidebar": [ + { + "type": "category", + "label": "Introduction", + "collapsible": false, + "items": [ + "README", + "code-of-conduct", + "releases", + "bugs", + "faq" + ] + }, + { + "type": "category", + "label": "Contribute", + "collapsible": false, + "items": [ + "contributing", + "contributing-docs-translations", + { + "type": "link", + "label": "Other Ways to Help", + "href": "/#help-the-flarum-project" + } + ] + }, + { + "type": "category", + "label": "Setting Up", + "collapsible": false, + "items": [ + "composer", + "install", + "update", + "troubleshoot" + ] + }, + { + "type": "category", + "label": "Management", + "collapsible": false, + "items": [ + "admin", + "config", + "extensions", + "languages", + "themes", + "mail", + "scheduler", + "console" + ] + }, + { + "type": "category", + "label": "Advanced", + "collapsible": false, + "items": [ + "rest-api", + "extenders" + ] + } + ], + "extendSidebar": [ + { + "type": "category", + "label": "Main Concepts", + "collapsible": false, + "items": [ + "extend/README", + "extend/start", + "extend/frontend", + "extend/routes", + "extend/models", + "extend/api", + "extend/distribution", + "extend/cli" + ] + }, + { + "type": "category", + "label": "Reference Guides", + "collapsible": false, + "items": [ + "extend/admin", + "extend/backend-events", + "extend/authorization", + "extend/frontend-pages", + "extend/interactive-components", + "extend/i18n", + "extend/language-packs", + "extend/forms", + "extend/permissions", + "extend/settings", + "extend/static-code-analysis", + "extend/testing", + "extend/theme", + "extend/views", + "extend/github-actions" + ] + }, + { + "type": "category", + "label": "Advanced Guides", + "collapsible": false, + "items": [ + "extend/api-throttling", + "extend/assets", + "extend/console", + "extend/extending-extensions", + "extend/extensibility", + "extend/filesystem", + "extend/formatting", + "extend/mail", + "extend/middleware", + "extend/model-visibility", + "extend/slugging", + "extend/notifications", + "extend/post-types", + "extend/search", + "extend/service-provider" + ] + }, + { + "type": "category", + "label": "Update Guides", + "collapsible": false, + "items": [ + "extend/update-1_x", + "extend/update-1_0", + "extend/update-b16", + "extend/update-b15", + "extend/update-b14", + "extend/update-b13", + "extend/update-b12", + "extend/update-b10", + "extend/update-b8" + ] + } + ], + "internalSidebar": [ + { + "type": "category", + "label": "Internal Docs", + "collapsible": false, + "items": [ + "internal/README", + "internal/merging-policy", + "internal/bundled-extensions-policy", + "internal/extension-manager" + ] + } + ] +} diff --git a/versions.json b/versions.json new file mode 100644 index 000000000..056f6d568 --- /dev/null +++ b/versions.json @@ -0,0 +1,3 @@ +[ + "1.x" +]