Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • AlekSIS/official/AlekSIS-App-Resint
  • sunweaver/AlekSIS-App-Resint
2 results
Show changes
Commits on Source (194)
Showing
with 743 additions and 33 deletions
module.exports = {
root: true,
overrides: [
{
files: ["*.js", "*.vue"],
// parser: "vue-eslint-parser",
//processor: "@graphql-eslint/graphql",
extends: [
"eslint:recommended",
"plugin:vue/strongly-recommended",
"plugin:@intlify/vue-i18n/recommended",
],
rules: {
"no-unused-vars": "warn",
"vue/no-unused-vars": "off",
"vue/multi-word-component-names": "off",
"vue/attribute-hyphenation": "error",
"vue/v-slot-style": "error",
"@intlify/vue-i18n/key-format-style": [
"error",
"snake_case",
{
splitByDots: false,
},
],
// "@intlify/vue-i18n/no-unused-keys": ["warn", {}],
"@intlify/vue-i18n/no-raw-text": [
"error",
{
ignoreNodes: ["v-icon"],
ignorePattern: "^[-–—·#:()\\[\\]&\\.\\s]+$",
},
],
"@intlify/vue-i18n/no-deprecated-tc": "off",
// Fixes for prettier (avoid eslint-config-prettier)
// The following rules can be used in some cases. See the README for more
// information. (These are marked with `0` instead of `"off"` so that a
// script can distinguish them.)
curly: 0,
"lines-around-comment": 0,
"max-len": 0,
"no-confusing-arrow": 0,
"no-mixed-operators": 0,
"no-tabs": 0,
"no-unexpected-multiline": 0,
quotes: 0,
"@typescript-eslint/quotes": 0,
"babel/quotes": 0,
"vue/html-self-closing": 0,
"vue/max-len": 0,
// The rest are rules that you never need to enable when using Prettier.
"array-bracket-newline": "off",
"array-bracket-spacing": "off",
"array-element-newline": "off",
"arrow-parens": "off",
"arrow-spacing": "off",
"block-spacing": "off",
"brace-style": "off",
"comma-dangle": "off",
"comma-spacing": "off",
"comma-style": "off",
"computed-property-spacing": "off",
"dot-location": "off",
"eol-last": "off",
"func-call-spacing": "off",
"function-call-argument-newline": "off",
"function-paren-newline": "off",
"generator-star": "off",
"generator-star-spacing": "off",
"implicit-arrow-linebreak": "off",
indent: "off",
"jsx-quotes": "off",
"key-spacing": "off",
"keyword-spacing": "off",
"linebreak-style": "off",
"multiline-ternary": "off",
"newline-per-chained-call": "off",
"new-parens": "off",
"no-arrow-condition": "off",
"no-comma-dangle": "off",
"no-extra-parens": "off",
"no-extra-semi": "off",
"no-floating-decimal": "off",
"no-mixed-spaces-and-tabs": "off",
"no-multi-spaces": "off",
"no-multiple-empty-lines": "off",
"no-reserved-keys": "off",
"no-space-before-semi": "off",
"no-trailing-spaces": "off",
"no-whitespace-before-property": "off",
"no-wrap-func": "off",
"nonblock-statement-body-position": "off",
"object-curly-newline": "off",
"object-curly-spacing": "off",
"object-property-newline": "off",
"one-var-declaration-per-line": "off",
"operator-linebreak": "off",
"padded-blocks": "off",
"quote-props": "off",
"rest-spread-spacing": "off",
semi: "off",
"semi-spacing": "off",
"semi-style": "off",
"space-after-function-name": "off",
"space-after-keywords": "off",
"space-before-blocks": "off",
"space-before-function-paren": "off",
"space-before-function-parentheses": "off",
"space-before-keywords": "off",
"space-in-brackets": "off",
"space-in-parens": "off",
"space-infix-ops": "off",
"space-return-throw-case": "off",
"space-unary-ops": "off",
"space-unary-word-ops": "off",
"switch-colon-spacing": "off",
"template-curly-spacing": "off",
"template-tag-spacing": "off",
"unicode-bom": "off",
"wrap-iife": "off",
"wrap-regex": "off",
"yield-star-spacing": "off",
"@babel/object-curly-spacing": "off",
"@babel/semi": "off",
"@typescript-eslint/brace-style": "off",
"@typescript-eslint/comma-dangle": "off",
"@typescript-eslint/comma-spacing": "off",
"@typescript-eslint/func-call-spacing": "off",
"@typescript-eslint/indent": "off",
"@typescript-eslint/keyword-spacing": "off",
"@typescript-eslint/member-delimiter-style": "off",
"@typescript-eslint/no-extra-parens": "off",
"@typescript-eslint/no-extra-semi": "off",
"@typescript-eslint/object-curly-spacing": "off",
"@typescript-eslint/semi": "off",
"@typescript-eslint/space-before-blocks": "off",
"@typescript-eslint/space-before-function-paren": "off",
"@typescript-eslint/space-infix-ops": "off",
"@typescript-eslint/type-annotation-spacing": "off",
"babel/object-curly-spacing": "off",
"babel/semi": "off",
"flowtype/boolean-style": "off",
"flowtype/delimiter-dangle": "off",
"flowtype/generic-spacing": "off",
"flowtype/object-type-curly-spacing": "off",
"flowtype/object-type-delimiter": "off",
"flowtype/quotes": "off",
"flowtype/semi": "off",
"flowtype/space-after-type-colon": "off",
"flowtype/space-before-generic-bracket": "off",
"flowtype/space-before-type-colon": "off",
"flowtype/union-intersection-spacing": "off",
"react/jsx-child-element-spacing": "off",
"react/jsx-closing-bracket-location": "off",
"react/jsx-closing-tag-location": "off",
"react/jsx-curly-newline": "off",
"react/jsx-curly-spacing": "off",
"react/jsx-equals-spacing": "off",
"react/jsx-first-prop-new-line": "off",
"react/jsx-indent": "off",
"react/jsx-indent-props": "off",
"react/jsx-max-props-per-line": "off",
"react/jsx-newline": "off",
"react/jsx-one-expression-per-line": "off",
"react/jsx-props-no-multi-spaces": "off",
"react/jsx-tag-spacing": "off",
"react/jsx-wrap-multilines": "off",
"standard/array-bracket-even-spacing": "off",
"standard/computed-property-even-spacing": "off",
"standard/object-curly-even-spacing": "off",
"unicorn/empty-brace-spaces": "off",
"unicorn/no-nested-ternary": "off",
"unicorn/number-literal-case": "off",
"vue/array-bracket-newline": "off",
"vue/array-bracket-spacing": "off",
"vue/arrow-spacing": "off",
"vue/block-spacing": "off",
"vue/block-tag-newline": "off",
"vue/brace-style": "off",
"vue/comma-dangle": "off",
"vue/comma-spacing": "off",
"vue/comma-style": "off",
"vue/dot-location": "off",
"vue/func-call-spacing": "off",
"vue/html-closing-bracket-newline": "off",
"vue/html-closing-bracket-spacing": "off",
"vue/html-end-tags": "off",
"vue/html-indent": "off",
"vue/html-quotes": "off",
"vue/key-spacing": "off",
"vue/keyword-spacing": "off",
"vue/max-attributes-per-line": "off",
"vue/multiline-html-element-content-newline": "off",
"vue/multiline-ternary": "off",
"vue/mustache-interpolation-spacing": "off",
"vue/no-extra-parens": "off",
"vue/no-multi-spaces": "off",
"vue/no-spaces-around-equal-signs-in-attribute": "off",
"vue/object-curly-newline": "off",
"vue/object-curly-spacing": "off",
"vue/object-property-newline": "off",
"vue/operator-linebreak": "off",
"vue/quote-props": "off",
"vue/script-indent": "off",
"vue/singleline-html-element-content-newline": "off",
"vue/space-in-parens": "off",
"vue/space-infix-ops": "off",
"vue/space-unary-ops": "off",
"vue/template-curly-spacing": "off",
},
settings: {
"vue-i18n": {
localeDir: "./aleksis/core/frontend/messages/*.{json}",
messageSyntaxVersion: "^8.0.0",
},
},
env: {
es2021: true,
},
parserOptions: {
ecmaVersion: "latest",
},
},
{
files: ["*.graphql"],
parser: "@graphql-eslint/eslint-plugin",
plugins: ["@graphql-eslint"],
extends: "plugin:@graphql-eslint/operations-recommended",
parserOptions: {
graphQLConfig: {
schema: "./schema.json",
documents: "../aleksis/**/*/frontend/**/*.graphql",
},
},
rules: {
"@graphql-eslint/no-anonymous-operations": "error",
"@graphql-eslint/no-duplicate-fields": "error",
"@graphql-eslint/naming-convention": [
"error",
{
OperationDefinition: {
style: "camelCase",
forbiddenPrefixes: ["Query", "Mutation", "Subscription", "Get"],
forbiddenSuffixes: ["Query", "Mutation", "Subscription"],
},
},
],
},
},
],
};
{
"name": "aleksis-builddeps",
"version": "1.0.0",
"dependencies": {
"@graphql-eslint/eslint-plugin": "^4.3.0",
"@intlify/eslint-plugin-vue-i18n": "^3.0.0",
"eslint": "^8.26.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-vue": "^9.7.0",
"graphql": "^16.10.0",
"prettier": "^3.4.0",
"stylelint": "^15.0.0",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-standard": "^34.0.0"
}
}
<!-- AlekSIS is developed on EduGit. GitHub only serves as
backup mirror and to help people find the project. If
possible, please submit your merge request on EduGit!
EduGit accepts logins with GitHub accounts.
-->
[ ] I have read the above and have no way to contribute on EduGit
[ ] I understand that GitHub's terms of service exclude young and
learning contributors, but still cannot contribute on EduGit
instead.
......@@ -48,13 +48,51 @@ venv/
DEADJOE
\#*#
# IntelliJ
.idea
.idea/
# VSCode
.vscode/
.history/
*.code-workspace
# Database
db.sqlite3
# Sphinx
docs/_build/
# Testing
.tox
# TeX
*.aux
# Generated files
/cache
/node_modules
.dev-js/node_modules
/static/
/whoosh_index/
.vite
.dev-js/.yarn
.dev-js/.pnp.cjs
.dev-js/.pnp.loader.mjs
.dev-js/.yarnrc.yml
.dev-js/schema.json
# Lock files
poetry.lock
package-lock.json
yarn.lock
.dev-js/yarn.lock
# Tests
.coverage
.mypy_cache/
.tox/
htmlcov/
# Data
maintenance_mode_state.txt
media/
aleksis/core/static/style.css
include:
- project: "AlekSIS/official/AlekSIS"
file: /ci/general.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test/lint.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test/security.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/build/dist.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/publish/pypi.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/general.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/prepare/lock.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test/lint.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test/security.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/build/dist.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/build/docs.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/publish/pypi.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/deploy/pages.yml
# Byte-compiled / optimized / DLL files
*$py.class
*.py[cod]
__pycache__/
# Distribution / packaging
*.egg
*.egg-info/
.Python
.eggs/
.installed.cfg
build/
develop-eggs/
dist/
downloads/
eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
# Installer logs
pip-delete-this-directory.txt
pip-log.txt
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# pyenv
.python-version
# Environments
.env
.venv
ENV/
env/
venv/
# Editors
*~
DEADJOE
\#*#
# IntelliJ
.idea
.idea/
# Database
db.sqlite3
# Sphinx
docs/_build/
# TeX
*.aux
# Generated files
/node_modules/
/static/
/whoosh_index/
poetry.lock
.coverage
.mypy_cache/
.tox/
htmlcov/
maintenance_mode_state.txt
media/
package-lock.json
yarn.lock
# VSCode
.vscode/
.history/
*.code-workspace
/cache
# Add HTML files to avoid problems with unsupported Django templates
*.html
# Do not check/reformat generated files
aleksis/core/util/licenses.json
.vite/
.pnp.cjs
.pnp.loader.mjs
.git/
......@@ -12,8 +12,103 @@ Unreleased
Added
~~~~~
* Menu icon changes when entry is selected.
`3.1`_ – 2023-07-17
-------------------
Added
~~~~~
* Support public live documents
Fixed
~~~~~
* API urls were in the wrong namespace.
`3.0`_ - 2023-05-12
-------------------
Nothing changed.
`3.0b2`_ - 2023-03-20
---------------------
Fixed
~~~~~
* Menu item was shown for all users independent of permissions.
`3.0b1`_ - 2023-03-09
---------------------
Fixed
~~~~~
* Provide PDF documents outside django/ URL namespace again
`3.0b0`_ - 2023-02-16
---------------------
This version requires AlekSIS-Core 3.0. It is incompatible with any previous
version.
Removed
~~~~~~~
* Legacy menu integration for AlekSIS-Core pre-3.0
Added
~~~~~
* Add SPA support for AlekSIS-Core 3.0
`2.2`_ - 2022-06-23
-------------------
Added
~~~~~
* Add Ukrainian locale (contributed by Sergiy Gorichenko from Fre(i)e Software GmbH).
`2.1`_ - 2022-01-12
-------------------
Added
~~~~~
* Open poster group menu entries in new tab.
* [Dev] LiveDocument.update() now has a default implementaiton, rendering
``self.template`` using ``self.get_context_data()``
* End-user, admin and dev documentation
Fixed
~~~~~
* Live documents table showed two "Actions" columns.
* Menu was not correctly re-generated after creating or editing poster groups
* Button for creation of live documents was there even if there weren't any live document types registered.
`2.0`_ - 2021-12-27
-------------------
Nothing changed.
`2.0b1`_ - 2021-11-07
---------------------
Added
~~~~~
* Provide API view for accessing the current PDF file of a live document (secured with OAuth2).
Changed
~~~~~~~
* German translations were updated.
`2.0b0`_ - 2021-11-03
--------------------
......@@ -29,4 +124,13 @@ Added
.. _Keep a Changelog: https://keepachangelog.com/en/1.0.0/
.. _Semantic Versioning: https://semver.org/spec/v2.0.0.html
.. _2.0b0: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.0b0
.. _2.0b0: https://edugit.org/AlekSIS/official/AlekSIS-App-Resint/-/tags/2.0b0
.. _2.0b1: https://edugit.org/AlekSIS/official/AlekSIS-App-Resint/-/tags/2.0b1
.. _2.0: https://edugit.org/AlekSIS/official/AlekSIS-App-Resint/-/tags/2.0
.. _2.1: https://edugit.org/AlekSIS/official/AlekSIS-App-Resint/-/tags/2.1
.. _2.2: https://edugit.org/AlekSIS/official/AlekSIS-App-Resint/-/tags/2.2
.. _3.0b0: https://edugit.org/AlekSIS/official/AlekSIS-App-Resint/-/tags/3.0b0
.. _3.0b1: https://edugit.org/AlekSIS/official/AlekSIS-App-Resint/-/tags/3.0b1
.. _3.0b2: https://edugit.org/AlekSIS/official/AlekSIS-App-Resint/-/tags/3.0b2
.. _3.0: https://edugit.org/AlekSIS/official/AlekSIS-App-Resint/-/tags/3.0
.. _3.1: https://edugit.org/AlekSIS/official/AlekSIS-App-Resint/-/tags/3.1
ARG APPS="AlekSIS-App-Resint"
FROM registry.edugit.org/aleksis/official/aleksis-core:master
......@@ -4,7 +4,7 @@ AlekSIS (School Information System) — App Resint (Public poster)
AlekSIS
-------
This is an application for use with the `AlekSIS`_ platform.
This is an application for use with the `AlekSIS®`_ platform.
Features
--------
......@@ -21,8 +21,9 @@ Licence
::
Copyright © 2018, 2019, 2020, 2021 Jonathan Weth <dev@jonathanweth.de>
Copyright © 2020, 2021 Frank Poetzsch-Heffter <p-h@katharineum.de>
Copyright © 2019 Julian Leucker <leuckeju@katharineum.de>
Copyright © 2020, 2021 Frank Poetzsch-Heffter <p-h@katharineum.de>
Copyright © 2022 Dominik George <dominik.george@teckids.org>
Licenced under the EUPL, version 1.2 or later
......@@ -31,5 +32,13 @@ full licence text or on the `European Union Public Licence`_ website
https://joinup.ec.europa.eu/collection/eupl/guidelines-users-and-developers
(including all other official language versions).
.. _AlekSIS: https://edugit.org/AlekSIS/official/AlekSIS
Trademark
---------
AlekSIS® is a registered trademark of the AlekSIS open source project, represented
by Teckids e.V. Please refer to the `trademark policy`_ for hints on using the trademark
AlekSIS®.
.. _AlekSIS®: https://edugit.org/AlekSIS/official/AlekSIS
.. _European Union Public Licence: https://eupl.eu/
.. _trademark policy: https://aleksis.org/pages/about
from django.apps import apps
from django.utils.translation import gettext as _
from django.db import models
from django.db.models import functions
from django.utils.translation import gettext_lazy as _
from aleksis.core.util.apps import AppConfig
......@@ -14,17 +16,26 @@ class ResintConfig(AppConfig):
licence = "EUPL-1.2+"
copyright_info = (
([2018, 2019, 2020, 2021], "Jonathan Weth", "dev@jonathanweth.de"),
([2020, 2021], "Frank Poetzsch-Heffter", "p-h@katharineum.de"),
([2019], "Julian Leucker", "leuckeju@katharineum.de"),
([2020, 2021], "Frank Poetzsch-Heffter", "p-h@katharineum.de"),
([2022], "Dominik George", "dominik.george@teckids.org"),
)
@classmethod
def get_all_scopes(cls) -> dict[str, str]:
"""Return all OAuth scopes and their descriptions for this app."""
LiveDocument = apps.get_model("resint", "LiveDocument")
scopes = {}
for live_document in LiveDocument.objects.all():
scopes[live_document.scope] = _("Access PDF file for live document {}").format(
live_document.name
label_prefix = _("Access PDF file for live document")
scopes = dict(
LiveDocument.objects.annotate(
scope=functions.Concat(
models.Value(f"{LiveDocument.SCOPE_PREFIX}_"),
models.F("slug"),
output_field=models.CharField(),
),
label=functions.Concat(models.Value(f"{label_prefix}: "), models.F("name")),
)
.values_list("scope", "label")
.distinct()
)
return scopes
export default {
meta: {
inMenu: true,
titleKey: "resint.menu_title",
icon: "mdi-open-in-app",
permission: "resint.view_menu_rule",
},
children: [
{
path: "",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "resint.posterIndex",
meta: {
inMenu: true,
titleKey: "resint.manage_posters.menu_title",
icon: "mdi-file-upload-outline",
iconActive: "mdi-file-upload",
permission: "resint.view_posters_rule",
},
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "upload/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "resint.posterUpload",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: ":pk/edit/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "resint.posterEdit",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: ":pk/delete/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "resint.posterDelete",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "groups/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "resint.posterGroupList",
meta: {
inMenu: true,
titleKey: "resint.poster_groups.menu_title",
icon: "mdi-folder-multiple-outline",
iconActive: "mdi-folder-multiple",
permission: "resint.view_postergroups_rule",
},
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "groups/create/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "resint.createPosterGroup",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "groups/:pk/edit/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "resint.editPosterGroup",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "groups/:pk/delete/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "resint.deletePosterGroup",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "live/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "resint.liveDocuments",
meta: {
inMenu: true,
titleKey: "resint.live_documents.menu_title",
icon: "mdi-update",
permission: "resint.view_livedocuments_rule",
},
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "live/:app/:model/create/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "resint.createLiveDocument",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "live/:pk/edit/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "resint.editLiveDocument",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "live_documents/:pk/delete/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "resint.deleteLiveDocument",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
],
};
{}
{
"resint": {
"menu_title": "Dokumente",
"manage_posters": {
"menu_title": "Dokumente verwalten"
},
"poster_groups": {
"menu_title": "Dokumentengruppen"
},
"live_documents": {
"menu_title": "Live-Dokumente"
}
}
}
{
"resint": {
"menu_title": "Documents",
"manage_posters": {
"menu_title": "Manage posters"
},
"poster_groups": {
"menu_title": "Poster groups"
},
"live_documents": {
"menu_title": "Live documents"
}
}
}
{}
{}
{}
{
"resint": {
"menu_title": "Документы",
"manage_posters": {
"menu_title": "Управление документами"
},
"poster_groups": {
"menu_title": "Группы документов"
},
"live_documents": {
"menu_title": "Онлайн-документы"
}
}
}
{}
{
"resint": {
"menu_title": "Документи",
"manage_posters": {
"menu_title": "Керування документами"
},
"poster_groups": {
"menu_title": "Групи документів"
},
"live_documents": {
"menu_title": "Онлайн-документи"
}
}
}