├── .dockerignore
├── .github
└── workflows
│ └── docker.yml
├── .gitignore
├── .php-cs-fixer.dist.php
├── LICENSE.md
├── Makefile
├── README.md
├── bin
├── cron_worker.php
└── task_worker.php
├── composer
├── composer.json
├── composer.lock
├── config
└── vars.php
├── docker-compose.dev.yml
├── docker-compose.yml
├── docker
├── Dockerfile
└── rootfs
│ ├── bin
│ └── docker-entrypoint.sh
│ ├── docker-entrypoint-init.d
│ └── 01-uname.sh
│ ├── etc
│ ├── nginx
│ │ └── nginx.conf
│ └── service
│ │ ├── cron
│ │ └── run
│ │ ├── nginx
│ │ └── run
│ │ └── php
│ │ └── run
│ └── usr
│ └── local
│ └── etc
│ └── php
│ └── conf.d
│ └── custom.ini
├── image.jpeg
├── orm
├── phinx
├── phinx.php
├── phpcs
├── phpunit
├── phpunit.xml
├── plugin
└── installed.php
├── public
├── assets
│ ├── css
│ │ ├── atlantis.css
│ │ └── bootstrap.min.css
│ ├── img
│ │ ├── icon
│ │ │ ├── 100.png
│ │ │ ├── 1024.png
│ │ │ ├── 114.png
│ │ │ ├── 120.png
│ │ │ ├── 128.png
│ │ │ ├── 144.png
│ │ │ ├── 152.png
│ │ │ ├── 16.png
│ │ │ ├── 167.png
│ │ │ ├── 180.png
│ │ │ ├── 192.png
│ │ │ ├── 20.png
│ │ │ ├── 256.png
│ │ │ ├── 29.png
│ │ │ ├── 32.png
│ │ │ ├── 40.png
│ │ │ ├── 50.png
│ │ │ ├── 512.png
│ │ │ ├── 57.png
│ │ │ ├── 58.png
│ │ │ ├── 60.png
│ │ │ ├── 64.png
│ │ │ ├── 72.png
│ │ │ ├── 76.png
│ │ │ ├── 80.png
│ │ │ └── 87.png
│ │ ├── lviv.jpg
│ │ ├── no_image.jpeg
│ │ └── no_image.png
│ └── js
│ │ ├── core
│ │ ├── bootstrap-tagsinput.min.js
│ │ ├── bootstrap.min.js
│ │ ├── chart.min.js
│ │ ├── jquery.3.7.1.min.js
│ │ ├── moment-timezone-with-data.js
│ │ ├── moment-with-locales.min.js
│ │ ├── moment.min.js
│ │ ├── popper.min.js
│ │ └── tooltip.min.js
│ │ ├── cup
│ │ └── script.js
│ │ ├── plugin
│ │ ├── bootstrap-notify
│ │ │ └── bootstrap-notify.min.js
│ │ ├── clusterize
│ │ │ ├── clusterize.min.css
│ │ │ └── clusterize.min.js
│ │ ├── codemirror
│ │ │ ├── addon
│ │ │ │ ├── dialog
│ │ │ │ │ ├── dialog.css
│ │ │ │ │ └── dialog.js
│ │ │ │ ├── edit
│ │ │ │ │ └── matchbrackets.js
│ │ │ │ ├── mode
│ │ │ │ │ ├── loadmode.js
│ │ │ │ │ ├── multiplex.js
│ │ │ │ │ ├── multiplex_test.js
│ │ │ │ │ ├── overlay.js
│ │ │ │ │ └── simple.js
│ │ │ │ ├── search
│ │ │ │ │ ├── jump-to-line.js
│ │ │ │ │ ├── search.js
│ │ │ │ │ └── searchcursor.js
│ │ │ │ └── selection
│ │ │ │ │ ├── active-line.js
│ │ │ │ │ ├── mark-selection.js
│ │ │ │ │ └── selection-pointer.js
│ │ │ ├── lib
│ │ │ │ ├── codemirror.css
│ │ │ │ └── codemirror.js
│ │ │ └── mode
│ │ │ │ ├── css
│ │ │ │ ├── css.js
│ │ │ │ ├── gss.html
│ │ │ │ ├── gss_test.js
│ │ │ │ ├── index.html
│ │ │ │ ├── less.html
│ │ │ │ ├── less_test.js
│ │ │ │ ├── scss.html
│ │ │ │ ├── scss_test.js
│ │ │ │ └── test.js
│ │ │ │ ├── htmlmixed
│ │ │ │ ├── htmlmixed.js
│ │ │ │ └── index.html
│ │ │ │ ├── index.html
│ │ │ │ ├── javascript
│ │ │ │ ├── index.html
│ │ │ │ ├── javascript.js
│ │ │ │ ├── json-ld.html
│ │ │ │ ├── test.js
│ │ │ │ └── typescript.html
│ │ │ │ ├── markdown
│ │ │ │ ├── index.html
│ │ │ │ ├── markdown.js
│ │ │ │ └── test.js
│ │ │ │ ├── meta.js
│ │ │ │ ├── twig
│ │ │ │ ├── index.html
│ │ │ │ └── twig.js
│ │ │ │ └── xml
│ │ │ │ ├── index.html
│ │ │ │ ├── test.js
│ │ │ │ └── xml.js
│ │ ├── dropzone
│ │ │ └── dropzone.min.js
│ │ ├── froala
│ │ │ ├── froala_editor.pkgd.css
│ │ │ ├── froala_editor.pkgd.js
│ │ │ └── froala_style.css
│ │ ├── jquery-scrollbar
│ │ │ └── jquery.scrollbar.min.js
│ │ ├── jquery-ui-1.12.1.custom
│ │ │ └── jquery-ui.min.js
│ │ ├── jquery-ui-touch-punch
│ │ │ └── jquery.ui.touch-punch.min.js
│ │ ├── jquery.modal
│ │ │ ├── jquery.modal.min.css
│ │ │ └── jquery.modal.min.js
│ │ ├── select2
│ │ │ └── select2.full.min.js
│ │ └── sweetalert
│ │ │ └── sweetalert2.all.min.js
│ │ └── wse.js
├── index.php
├── resource
│ └── .gitkeep
└── uploads
│ └── .gitkeep
├── scheme
├── migrations
│ ├── 20240414153158.php
│ ├── 20240702092036.php
│ ├── 20240702092511.php
│ ├── 20240727135000.php
│ ├── 20240807113500.php
│ ├── 20240807122500.php
│ └── 20250226101251.php
└── seeds
│ └── ReferenceSeeder.php
├── src
├── Application
│ ├── Actions
│ │ ├── Api
│ │ │ ├── ActionApi.php
│ │ │ └── v1
│ │ │ │ ├── EntityAction.php
│ │ │ │ ├── SearchAction.php
│ │ │ │ ├── SignatureAction.php
│ │ │ │ └── TelemetryAction.php
│ │ ├── Auth
│ │ │ ├── AuthAction.php
│ │ │ ├── LoginAction.php
│ │ │ ├── LogoutAction.php
│ │ │ ├── RefreshTokenAction.php
│ │ │ ├── RegisterAction.php
│ │ │ └── RevokeTokenAction.php
│ │ ├── Common
│ │ │ ├── Catalog
│ │ │ │ ├── CartAction.php
│ │ │ │ ├── CartDoneAction.php
│ │ │ │ ├── CatalogAction.php
│ │ │ │ └── ListAction.php
│ │ │ ├── File
│ │ │ │ ├── FileAction.php
│ │ │ │ ├── FileGetAction.php
│ │ │ │ ├── FileUploadAction.php
│ │ │ │ └── FileViewAction.php
│ │ │ ├── ForbiddenPageAction.php
│ │ │ ├── FormAction.php
│ │ │ ├── GuestBookAction.php
│ │ │ ├── MainPageAction.php
│ │ │ ├── PageAction.php
│ │ │ ├── Publication
│ │ │ │ └── ListAction.php
│ │ │ ├── SearchAction.php
│ │ │ ├── User
│ │ │ │ ├── UserAction.php
│ │ │ │ ├── UserLoginAction.php
│ │ │ │ ├── UserLogoutAction.php
│ │ │ │ ├── UserProfileAction.php
│ │ │ │ ├── UserRegisterAction.php
│ │ │ │ ├── UserRevokeTokenAction.php
│ │ │ │ └── UserSubscribeAction.php
│ │ │ └── XMLFileAction.php
│ │ └── Cup
│ │ │ ├── Catalog
│ │ │ ├── Attribute
│ │ │ │ ├── AttributeCreateAction.php
│ │ │ │ ├── AttributeDeleteAction.php
│ │ │ │ ├── AttributeListAction.php
│ │ │ │ └── AttributeUpdateAction.php
│ │ │ ├── CatalogAction.php
│ │ │ ├── Category
│ │ │ │ ├── CategoryCreateAction.php
│ │ │ │ ├── CategoryDeleteAction.php
│ │ │ │ ├── CategoryListAction.php
│ │ │ │ └── CategoryUpdateAction.php
│ │ │ ├── CategoryStatisticAction.php
│ │ │ ├── Order
│ │ │ │ ├── OrderCreateAction.php
│ │ │ │ ├── OrderDeleteAction.php
│ │ │ │ ├── OrderDispatchAction.php
│ │ │ │ ├── OrderDocumentAction.php
│ │ │ │ ├── OrderExportAction.php
│ │ │ │ ├── OrderListAction.php
│ │ │ │ └── OrderUpdateAction.php
│ │ │ └── Product
│ │ │ │ ├── ProductCreateAction.php
│ │ │ │ ├── ProductDeleteAction.php
│ │ │ │ ├── ProductExportAction.php
│ │ │ │ ├── ProductImportAction.php
│ │ │ │ ├── ProductListAction.php
│ │ │ │ └── ProductUpdateAction.php
│ │ │ ├── EditorPageAction.php
│ │ │ ├── File
│ │ │ ├── FileAction.php
│ │ │ ├── FileDeleteAction.php
│ │ │ ├── FileListAction.php
│ │ │ └── Image
│ │ │ │ ├── DeleteAction.php
│ │ │ │ └── GetAction.php
│ │ │ ├── ForbiddenPageAction.php
│ │ │ ├── Form
│ │ │ ├── Data
│ │ │ │ ├── DataDeleteAction.php
│ │ │ │ ├── DataListAction.php
│ │ │ │ ├── DataPreviewAction.php
│ │ │ │ └── DataViewAction.php
│ │ │ ├── FormAction.php
│ │ │ ├── FormCreateAction.php
│ │ │ ├── FormDeleteAction.php
│ │ │ ├── FormListAction.php
│ │ │ └── FormUpdateAction.php
│ │ │ ├── GuestBook
│ │ │ ├── GuestBookAction.php
│ │ │ ├── GuestBookDeleteAction.php
│ │ │ ├── GuestBookListAction.php
│ │ │ └── GuestBookUpdateAction.php
│ │ │ ├── LogPageAction.php
│ │ │ ├── LoginPageAction.php
│ │ │ ├── MainPageAction.php
│ │ │ ├── Page
│ │ │ ├── PageAction.php
│ │ │ ├── PageCreateAction.php
│ │ │ ├── PageDeleteAction.php
│ │ │ ├── PageListAction.php
│ │ │ └── PageUpdateAction.php
│ │ │ ├── ParametersPageAction.php
│ │ │ ├── Publication
│ │ │ ├── Category
│ │ │ │ ├── CategoryCreateAction.php
│ │ │ │ ├── CategoryDeleteAction.php
│ │ │ │ ├── CategoryListAction.php
│ │ │ │ └── CategoryUpdateAction.php
│ │ │ ├── PublicationAction.php
│ │ │ ├── PublicationCreateAction.php
│ │ │ ├── PublicationDeleteAction.php
│ │ │ ├── PublicationListAction.php
│ │ │ ├── PublicationPreviewAction.php
│ │ │ └── PublicationUpdateAction.php
│ │ │ ├── Reference
│ │ │ ├── ReferenceAction.php
│ │ │ ├── ReferenceCreateAction.php
│ │ │ ├── ReferenceDeleteAction.php
│ │ │ ├── ReferenceListAction.php
│ │ │ └── ReferenceUpdateAction.php
│ │ │ ├── RefreshAction.php
│ │ │ ├── SystemPageAction.php
│ │ │ ├── TaskRunAction.php
│ │ │ └── User
│ │ │ ├── Group
│ │ │ ├── CreateAction.php
│ │ │ ├── DeleteAction.php
│ │ │ ├── ListAction.php
│ │ │ └── UpdateAction.php
│ │ │ ├── NewsLetter
│ │ │ └── CreateAction.php
│ │ │ ├── Subscriber
│ │ │ ├── CreateAction.php
│ │ │ ├── DeleteAction.php
│ │ │ └── ListAction.php
│ │ │ ├── UserAction.php
│ │ │ ├── UserCreateAction.php
│ │ │ ├── UserDeleteAction.php
│ │ │ ├── UserListAction.php
│ │ │ ├── UserUpdateAction.php
│ │ │ └── UserViewAction.php
│ ├── Auth.php
│ ├── Auth
│ │ ├── AbstractAuthProvider.php
│ │ ├── BasicAuthProvider.php
│ │ └── OpenAuthProvider.php
│ ├── Mail.php
│ ├── Mail
│ │ ├── MailProviderInterface.php
│ │ ├── SMTPProvider.php
│ │ └── SPProvider.php
│ ├── Middlewares
│ │ ├── AccessCheckerMiddleware.php
│ │ ├── AuthorizationAPIMiddleware.php
│ │ ├── AuthorizationMiddleware.php
│ │ ├── CORSMiddleware.php
│ │ ├── IsRouteEnabledAPIMiddleware.php
│ │ ├── IsRouteEnabledMiddleware.php
│ │ ├── IsSiteEnabledMiddleware.php
│ │ ├── LocaleMiddleware.php
│ │ ├── NonWWWMiddleware.php
│ │ └── PluginMiddleware.php
│ ├── PubSub.php
│ ├── Twig
│ │ ├── LocaleNode.php
│ │ └── LocaleParser.php
│ ├── TwigExtension.php
│ └── i18n.php
├── Domain
│ ├── AbstractAction.php
│ ├── AbstractException.php
│ ├── AbstractExtension.php
│ ├── AbstractHttpException.php
│ ├── AbstractMiddleware.php
│ ├── AbstractNotFoundException.php
│ ├── AbstractPlugin.php
│ ├── AbstractSchedule.php
│ ├── AbstractService.php
│ ├── AbstractTask.php
│ ├── Casts
│ │ ├── AddressUrl.php
│ │ ├── Boolean.php
│ │ ├── Catalog
│ │ │ ├── Attribute
│ │ │ │ └── Type.php
│ │ │ ├── Order
│ │ │ │ └── Delivery.php
│ │ │ ├── Product
│ │ │ │ ├── Dimension.php
│ │ │ │ ├── Tags.php
│ │ │ │ └── Type.php
│ │ │ └── Status.php
│ │ ├── Decimal.php
│ │ ├── Email.php
│ │ ├── Enum.php
│ │ ├── GuestBook
│ │ │ └── Status.php
│ │ ├── Json.php
│ │ ├── Meta.php
│ │ ├── Page
│ │ │ └── Type.php
│ │ ├── Phone.php
│ │ ├── Reference
│ │ │ └── Type.php
│ │ ├── Sort.php
│ │ ├── Task
│ │ │ └── Status.php
│ │ ├── User
│ │ │ ├── Company.php
│ │ │ ├── Legal.php
│ │ │ ├── Messenger.php
│ │ │ ├── Password.php
│ │ │ └── Status.php
│ │ └── Uuid.php
│ ├── Exceptions
│ │ ├── FileNotFoundException.php
│ │ ├── HttpBadRequestException.php
│ │ ├── HttpForbiddenException.php
│ │ ├── HttpMethodNotAllowedException.php
│ │ ├── HttpNotFoundException.php
│ │ ├── HttpNotImplementedException.php
│ │ ├── HttpRedirectException.php
│ │ ├── JWTExpiredException.php
│ │ ├── NullPointException.php
│ │ ├── WrongAuthProviderException.php
│ │ ├── WrongEmailValueException.php
│ │ ├── WrongIpValueException.php
│ │ └── WrongPhoneValueException.php
│ ├── Models
│ │ ├── CatalogAttribute.php
│ │ ├── CatalogCategory.php
│ │ ├── CatalogOrder.php
│ │ ├── CatalogProduct.php
│ │ ├── File.php
│ │ ├── Form.php
│ │ ├── FormData.php
│ │ ├── GuestBook.php
│ │ ├── Page.php
│ │ ├── Parameter.php
│ │ ├── Publication.php
│ │ ├── PublicationCategory.php
│ │ ├── Reference.php
│ │ ├── Task.php
│ │ ├── User.php
│ │ ├── UserGroup.php
│ │ ├── UserIntegration.php
│ │ ├── UserSubscriber.php
│ │ └── UserToken.php
│ ├── Plugin
│ │ ├── AbstractDeliveryPlugin.php
│ │ ├── AbstractLanguagePlugin.php
│ │ ├── AbstractLegacyPlugin.php
│ │ ├── AbstractMailPlugin.php
│ │ ├── AbstractOAuthPlugin.php
│ │ └── AbstractPaymentPlugin.php
│ ├── References
│ │ ├── Catalog.php
│ │ ├── Date.php
│ │ ├── Documents.php
│ │ ├── Publication.php
│ │ └── User.php
│ ├── Schedules
│ │ └── Test.php
│ ├── Service
│ │ ├── Catalog
│ │ │ ├── AttributeService.php
│ │ │ ├── CategoryService.php
│ │ │ ├── Exception
│ │ │ │ ├── AddressAlreadyExistsException.php
│ │ │ │ ├── AttributeNotFoundException.php
│ │ │ │ ├── CategoryNotFoundException.php
│ │ │ │ ├── MissingCategoryValueException.php
│ │ │ │ ├── MissingTitleValueException.php
│ │ │ │ ├── OrderNotFoundException.php
│ │ │ │ ├── OrderShippingLimitException.php
│ │ │ │ ├── ProductNotFoundException.php
│ │ │ │ ├── RelationNotFoundException.php
│ │ │ │ ├── TitleAlreadyExistsException.php
│ │ │ │ ├── WrongEmailValueException.php
│ │ │ │ ├── WrongPhoneValueException.php
│ │ │ │ └── WrongTitleValueException.php
│ │ │ ├── OrderService.php
│ │ │ └── ProductService.php
│ │ ├── File
│ │ │ ├── Exception
│ │ │ │ ├── FileAlreadyExistsException.php
│ │ │ │ └── FileNotFoundException.php
│ │ │ └── FileService.php
│ │ ├── Form
│ │ │ ├── DataService.php
│ │ │ ├── Exception
│ │ │ │ ├── AddressAlreadyExistsException.php
│ │ │ │ ├── FormDataNotFoundException.php
│ │ │ │ ├── FormNotFoundException.php
│ │ │ │ ├── MissingMessageValueException.php
│ │ │ │ ├── MissingTitleValueException.php
│ │ │ │ ├── TitleAlreadyExistsException.php
│ │ │ │ └── WrongTitleValueException.php
│ │ │ └── FormService.php
│ │ ├── GuestBook
│ │ │ ├── Exception
│ │ │ │ ├── EntryNotFoundException.php
│ │ │ │ ├── MissingEmailValueException.php
│ │ │ │ ├── MissingMessageValueException.php
│ │ │ │ ├── MissingNameValueException.php
│ │ │ │ ├── WrongEmailValueException.php
│ │ │ │ └── WrongNameValueException.php
│ │ │ └── GuestBookService.php
│ │ ├── Page
│ │ │ ├── Exception
│ │ │ │ ├── AddressAlreadyExistsException.php
│ │ │ │ ├── MissingTitleValueException.php
│ │ │ │ ├── PageNotFoundException.php
│ │ │ │ ├── TitleAlreadyExistsException.php
│ │ │ │ └── WrongTitleValueException.php
│ │ │ └── PageService.php
│ │ ├── Parameter
│ │ │ ├── Exception
│ │ │ │ ├── ParameterAlreadyExistsException.php
│ │ │ │ └── ParameterNotFoundException.php
│ │ │ └── ParameterService.php
│ │ ├── Publication
│ │ │ ├── CategoryService.php
│ │ │ ├── Exception
│ │ │ │ ├── AddressAlreadyExistsException.php
│ │ │ │ ├── CategoryNotFoundException.php
│ │ │ │ ├── MissingCategoryValueException.php
│ │ │ │ ├── MissingTitleValueException.php
│ │ │ │ ├── PublicationNotFoundException.php
│ │ │ │ ├── TitleAlreadyExistsException.php
│ │ │ │ └── WrongTitleValueException.php
│ │ │ └── PublicationService.php
│ │ ├── Reference
│ │ │ ├── Exception
│ │ │ │ ├── MissingTitleValueException.php
│ │ │ │ ├── MissingTypeValueException.php
│ │ │ │ ├── ReferenceNotFoundException.php
│ │ │ │ ├── TitleAlreadyExistsException.php
│ │ │ │ └── WrongTitleValueException.php
│ │ │ └── ReferenceService.php
│ │ ├── Task
│ │ │ ├── Exception
│ │ │ │ ├── MissingActionValueException.php
│ │ │ │ ├── MissingTitleValueException.php
│ │ │ │ ├── TaskNotFoundException.php
│ │ │ │ └── WrongTitleValueException.php
│ │ │ └── TaskService.php
│ │ └── User
│ │ │ ├── Exception
│ │ │ ├── EmailAlreadyExistsException.php
│ │ │ ├── EmailBannedException.php
│ │ │ ├── IntegrationNotFoundException.php
│ │ │ ├── MissingTitleValueException.php
│ │ │ ├── MissingUniqueValueException.php
│ │ │ ├── PhoneAlreadyExistsException.php
│ │ │ ├── TitleAlreadyExistsException.php
│ │ │ ├── TokenNotFoundException.php
│ │ │ ├── UserGroupNotFoundException.php
│ │ │ ├── UserNotFoundException.php
│ │ │ ├── UsernameAlreadyExistsException.php
│ │ │ ├── WrongCodeException.php
│ │ │ ├── WrongEmailValueException.php
│ │ │ ├── WrongIpValueException.php
│ │ │ ├── WrongPasswordException.php
│ │ │ ├── WrongPhoneValueException.php
│ │ │ ├── WrongTitleValueException.php
│ │ │ └── WrongUsernameValueException.php
│ │ │ ├── GroupService.php
│ │ │ ├── SubscriberService.php
│ │ │ ├── TokenService.php
│ │ │ └── UserService.php
│ ├── Tasks
│ │ ├── Catalog
│ │ │ └── ProductImportTask.php
│ │ ├── ConvertImageTask.php
│ │ ├── ReConvertImageTask.php
│ │ ├── SearchIndexTask.php
│ │ ├── SendJSONTask.php
│ │ ├── SendMailTask.php
│ │ └── SendNewsLetterMailTask.php
│ └── Traits
│ │ ├── HasFiles.php
│ │ ├── HasParameters.php
│ │ ├── HasRenderer.php
│ │ ├── HasStorage.php
│ │ └── UseSecurity.php
├── Locale
│ └── en-US.php
├── Template
│ ├── cup
│ │ ├── auth
│ │ │ ├── forbidden.twig
│ │ │ └── login.twig
│ │ ├── catalog
│ │ │ ├── attribute
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ ├── category
│ │ │ │ ├── form.twig
│ │ │ │ ├── index-item.twig
│ │ │ │ └── index.twig
│ │ │ ├── order
│ │ │ │ ├── dispatch.twig
│ │ │ │ ├── document-view.twig
│ │ │ │ ├── form-modal-product.twig
│ │ │ │ ├── form-modal-user.twig
│ │ │ │ ├── form-product-item.twig
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ ├── product
│ │ │ │ ├── form-modal-related.twig
│ │ │ │ ├── form.twig
│ │ │ │ ├── index-modal-import.twig
│ │ │ │ └── index.twig
│ │ │ └── statistic.twig
│ │ ├── donate.twig
│ │ ├── editor.twig
│ │ ├── editor
│ │ │ ├── index-aside-file.twig
│ │ │ ├── index-aside.twig
│ │ │ └── index.twig
│ │ ├── field.twig
│ │ ├── file
│ │ │ └── index.twig
│ │ ├── form-file.twig
│ │ ├── form-header.twig
│ │ ├── form-image.twig
│ │ ├── form-meta.twig
│ │ ├── form-save.twig
│ │ ├── form-tags.twig
│ │ ├── form.twig
│ │ ├── form
│ │ │ ├── form.twig
│ │ │ ├── index.twig
│ │ │ └── view
│ │ │ │ ├── detail.twig
│ │ │ │ └── list.twig
│ │ ├── guestbook
│ │ │ ├── form.twig
│ │ │ └── index.twig
│ │ ├── layout.twig
│ │ ├── logs.twig
│ │ ├── navigation.twig
│ │ ├── page
│ │ │ ├── form.twig
│ │ │ └── index.twig
│ │ ├── parameters
│ │ │ ├── field.twig
│ │ │ └── index.twig
│ │ ├── publication
│ │ │ ├── category
│ │ │ │ ├── form.twig
│ │ │ │ ├── index-item.twig
│ │ │ │ └── index.twig
│ │ │ ├── form.twig
│ │ │ ├── index.twig
│ │ │ └── preview.twig
│ │ ├── reference
│ │ │ ├── address-format
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ ├── countries
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ ├── currencies
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ ├── deliveries
│ │ │ │ ├── form-item.twig
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ ├── documents
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ ├── length-classes
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ ├── manufacturer
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ ├── order-status
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ ├── payments
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ ├── social-networks
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ ├── stock-status
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ ├── store-locations
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ ├── tax-rates
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ │ └── weight-classes
│ │ │ │ ├── form.twig
│ │ │ │ └── index.twig
│ │ ├── sidebar.twig
│ │ ├── system
│ │ │ ├── index-step-1.twig
│ │ │ ├── index-step-2.twig
│ │ │ ├── index-step-3.twig
│ │ │ └── index.twig
│ │ ├── toolbar.twig
│ │ └── user
│ │ │ ├── form.twig
│ │ │ ├── group
│ │ │ ├── form.twig
│ │ │ └── index.twig
│ │ │ ├── index.twig
│ │ │ ├── newsletter
│ │ │ └── form.twig
│ │ │ ├── subscriber
│ │ │ └── index.twig
│ │ │ └── view.twig
│ ├── errors
│ │ ├── p400.twig
│ │ ├── p403.twig
│ │ ├── p404.twig
│ │ ├── p405.twig
│ │ ├── p500.twig
│ │ └── p503.twig
│ ├── layout.twig
│ └── mixin
│ │ ├── adbd.twig
│ │ ├── catalog.twig
│ │ ├── cookies.twig
│ │ ├── datatable.twig
│ │ ├── form.twig
│ │ ├── gallery.twig
│ │ ├── img-script.twig
│ │ ├── img.twig
│ │ ├── picture.twig
│ │ ├── quiz.twig
│ │ └── recaptcha.twig
├── bootstrap.php
├── dependencies.php
├── helpers.php
├── middleware.php
├── routes.php
├── services.php
└── settings.php
├── tests
├── API
│ ├── CatalogCategoryAPITest.php
│ ├── CatalogProductAPITest.php
│ └── CommonAPITest.php
├── Domain
│ └── Service
│ │ ├── Catalog
│ │ ├── AttributeServiceTest.php
│ │ ├── AttributeTest.php
│ │ ├── CategoryServiceTest.php
│ │ ├── OrderServiceTest.php
│ │ └── ProductServiceTest.php
│ │ ├── File
│ │ └── FileServiceTest.php
│ │ ├── Form
│ │ ├── FormDataServiceTest.php
│ │ └── FormServiceTest.php
│ │ ├── GuestBook
│ │ └── GuestBookServiceTest.php
│ │ ├── Page
│ │ └── PageServiceTest.php
│ │ ├── Parameter
│ │ └── ParameterServiceTest.php
│ │ ├── Publication
│ │ ├── CategoryServiceTest.php
│ │ └── PublicationServiceTest.php
│ │ ├── Reference
│ │ └── ReferenceServiceTest.php
│ │ ├── Task
│ │ └── TaskServiceTest.php
│ │ └── User
│ │ ├── GroupServiceTest.php
│ │ ├── SubscriberServiceTest.php
│ │ ├── TokenServiceTest.php
│ │ └── UserServiceTest.php
└── TestCase.php
├── theme
└── default
│ ├── main.twig
│ ├── p400.twig
│ ├── p404.twig
│ ├── p405.twig
│ └── p500.twig
└── var
├── cache
└── .gitkeep
├── log
└── .gitkeep
├── upload
└── .gitkeep
└── xml
└── .gitkeep
/.dockerignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .git
3 | .composer
4 | hooks
5 | vendor
6 | .gitignore
7 | composer
8 | docker-compose.yml
9 | LICENSE.md
10 | README.md
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .vscode
3 | .DS_Store
4 |
5 | /theme/*
6 | !/theme/default
7 | !/theme/older
8 |
9 | /plugin/*
10 | !/plugin/installed.php
11 | /vendor/*
12 | !/vendor/.gitkeep
13 | /var/*.sqlite
14 | /var/*.sqlite-journal
15 | /var/*.key
16 | /var/cache/*
17 | !/var/cache/.gitkeep
18 | /var/log/*
19 | !/var/log/.gitkeep
20 | /var/upload/*
21 | !/var/upload/.gitkeep
22 | /var/xml/*.xml
23 | !/var/xml/.gitkeep
24 | /var/.lock
25 | /var/worker.pid
26 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2011-2024 Aleksey Ilyin (getwebspace.org)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is furnished
10 | to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | up:
2 | @docker-compose -f docker-compose.dev.yml up -d || :
3 | @docker-compose -f docker-compose.dev.yml exec platform composer install || :
4 | @chmod -R 0777 plugin || :
5 | @chmod -R 0777 public/resource || :
6 | @chmod -R 0777 theme || :
7 | @chmod -R 0777 var || :
8 | @docker-compose -f docker-compose.dev.yml exec platform ./vendor/bin/phinx migrate
9 |
10 | down:
11 | @docker-compose -f docker-compose.dev.yml down
12 |
13 | run-test:
14 | @docker-compose -f docker-compose.dev.yml exec platform ./vendor/bin/phpunit --color=always --configuration phpunit.xml
15 |
16 | run-lint:
17 | @docker-compose -f docker-compose.dev.yml exec platform ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php
18 |
19 | migrate-up:
20 | @docker-compose -f docker-compose.dev.yml exec platform ./vendor/bin/phinx migrate
21 |
22 | migrate-down:
23 | @docker-compose -f docker-compose.dev.yml exec platform ./vendor/bin/phinx rollback
24 |
25 | migrate-create:
26 | @docker-compose -f docker-compose.dev.yml exec platform ./vendor/bin/phinx create
27 |
28 | migrate-status:
29 | @docker-compose -f docker-compose.dev.yml exec platform ./vendor/bin/phinx status
30 |
--------------------------------------------------------------------------------
/bin/cron_worker.php:
--------------------------------------------------------------------------------
1 | getContainer();
19 |
20 | /** @var \Monolog\Logger $logger */
21 | $logger = $container->get(\Psr\Log\LoggerInterface::class);
22 |
23 | // simple scheduler
24 | $scheduler = $container->get('scheduler');
25 |
26 | // add jobs
27 | // $scheduler->register(\App\Domain\Schedules\Test::class, '*/5 * * * *');
28 |
29 | // check jobs
30 | foreach ($scheduler->get() as $scheduled) {
31 | $schedule = $scheduled['schedule'];
32 |
33 | /** @var \App\Domain\AbstractSchedule $job */
34 | $job = $scheduled['job'];
35 |
36 | if ($job->isShouldRun($schedule)) {
37 | $job->run();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/composer:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | docker run --rm --interactive --tty --dns 1.1.1.1 --volume $PWD:/app composer:2 --ignore-platform-reqs "$@"
4 |
--------------------------------------------------------------------------------
/config/vars.php:
--------------------------------------------------------------------------------
1 | &2 "*** Running: $script"
29 | $script
30 | retval=$?
31 | if [ $retval != 0 ]; then
32 | echo >&2 "*** Failed with return value: $?"
33 | exit $retval
34 | fi
35 | done
36 | echo "Finished startup scripts in /docker-entrypoint-init.d"
37 |
38 | echo "Starting runit..."
39 | exec runsvdir -P /etc/service &
40 |
41 | RUNSVDIR=$!
42 | echo "Started runsvdir, PID is $RUNSVDIR"
43 | echo "wait for processes to start...."
44 |
45 | sleep 5
46 | for _srv in $(ls -1 /etc/service); do
47 | sv status $_srv
48 | done
49 |
50 | # catch shutdown signals
51 | trap shutdown SIGTERM SIGHUP SIGQUIT SIGINT
52 | wait $RUNSVDIR
53 |
54 | shutdown
55 |
--------------------------------------------------------------------------------
/docker/rootfs/docker-entrypoint-init.d/01-uname.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Test file to check init scripts
3 | uname -a
4 |
--------------------------------------------------------------------------------
/docker/rootfs/etc/service/cron/run:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 |
3 | # pipe stderr to stdout and run cron
4 | exec 2>&1
5 | exec crond -f
6 |
--------------------------------------------------------------------------------
/docker/rootfs/etc/service/nginx/run:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 |
3 | # pipe stderr to stdout and run nginx omiting ENV vars to avoid security leaks
4 | exec 2>&1
5 | exec env - PATH=$PATH nginx -g 'daemon off;'
6 |
--------------------------------------------------------------------------------
/docker/rootfs/etc/service/php/run:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 |
3 | # pipe stderr to stdout and run php-fpm
4 | exec 2>&1
5 | exec php-fpm -F
6 |
--------------------------------------------------------------------------------
/docker/rootfs/usr/local/etc/php/conf.d/custom.ini:
--------------------------------------------------------------------------------
1 | short_open_tag= On
2 | memory_limit= 128M
3 | post_max_size= 64M
4 | upload_max_filesize= 32M
5 |
6 | [Date]
7 | date.timezone="UTC"
8 |
9 | [opcache]
10 | opcache.enable=1
11 | opcache.enable_cli=1
12 | opcache.jit_buffer_size=100M
13 | opcache.jit=1255
14 |
--------------------------------------------------------------------------------
/image.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/image.jpeg
--------------------------------------------------------------------------------
/orm:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | docker-compose exec platform vendor/bin/doctrine "$@"
4 |
--------------------------------------------------------------------------------
/phinx:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | docker-compose exec -e PHP_CS_FIXER_IGNORE_ENV=1 platform vendor/bin/phinx "$@"
4 |
--------------------------------------------------------------------------------
/phinx.php:
--------------------------------------------------------------------------------
1 | [
6 | 'migrations' => 'scheme/migrations',
7 | 'seeds' => 'scheme/seeds',
8 | ],
9 | 'environments' => [
10 | 'default_migration_table' => 'phinx_migrations',
11 | 'default_environment' => ($_ENV['TEST'] ?? false) ? 'dev' : 'prod',
12 | 'dev' => [
13 | 'dsn' => 'sqlite://./var/database-test',
14 | 'suffix' => '.sqlite',
15 | ],
16 | 'prod' => [
17 | 'dsn' => !empty($_ENV['DATABASE']) ? $_ENV['DATABASE'] : 'sqlite://./var/database',
18 | 'suffix' => '.sqlite',
19 | ],
20 | ],
21 | 'version_order' => 'creation',
22 | ];
23 |
--------------------------------------------------------------------------------
/phpcs:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | docker-compose exec -e PHP_CS_FIXER_IGNORE_ENV=1 platform vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php -v "$@"
4 |
--------------------------------------------------------------------------------
/phpunit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | docker-compose exec platform vendor/bin/phpunit --color=always --configuration phpunit.xml "$@"
4 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ./tests/
6 |
7 |
8 |
9 |
10 | ./src
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/plugin/installed.php:
--------------------------------------------------------------------------------
1 | get('plugin');
8 |
9 | // Example
10 | // $plugins->register(\Plugin\Example\ExamplePlugin::class);
11 | // $plugins->register(new \Plugin\Example\ExamplePlugin($container));
12 |
--------------------------------------------------------------------------------
/public/assets/img/icon/100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/100.png
--------------------------------------------------------------------------------
/public/assets/img/icon/1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/1024.png
--------------------------------------------------------------------------------
/public/assets/img/icon/114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/114.png
--------------------------------------------------------------------------------
/public/assets/img/icon/120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/120.png
--------------------------------------------------------------------------------
/public/assets/img/icon/128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/128.png
--------------------------------------------------------------------------------
/public/assets/img/icon/144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/144.png
--------------------------------------------------------------------------------
/public/assets/img/icon/152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/152.png
--------------------------------------------------------------------------------
/public/assets/img/icon/16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/16.png
--------------------------------------------------------------------------------
/public/assets/img/icon/167.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/167.png
--------------------------------------------------------------------------------
/public/assets/img/icon/180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/180.png
--------------------------------------------------------------------------------
/public/assets/img/icon/192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/192.png
--------------------------------------------------------------------------------
/public/assets/img/icon/20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/20.png
--------------------------------------------------------------------------------
/public/assets/img/icon/256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/256.png
--------------------------------------------------------------------------------
/public/assets/img/icon/29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/29.png
--------------------------------------------------------------------------------
/public/assets/img/icon/32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/32.png
--------------------------------------------------------------------------------
/public/assets/img/icon/40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/40.png
--------------------------------------------------------------------------------
/public/assets/img/icon/50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/50.png
--------------------------------------------------------------------------------
/public/assets/img/icon/512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/512.png
--------------------------------------------------------------------------------
/public/assets/img/icon/57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/57.png
--------------------------------------------------------------------------------
/public/assets/img/icon/58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/58.png
--------------------------------------------------------------------------------
/public/assets/img/icon/60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/60.png
--------------------------------------------------------------------------------
/public/assets/img/icon/64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/64.png
--------------------------------------------------------------------------------
/public/assets/img/icon/72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/72.png
--------------------------------------------------------------------------------
/public/assets/img/icon/76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/76.png
--------------------------------------------------------------------------------
/public/assets/img/icon/80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/80.png
--------------------------------------------------------------------------------
/public/assets/img/icon/87.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/icon/87.png
--------------------------------------------------------------------------------
/public/assets/img/lviv.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/lviv.jpg
--------------------------------------------------------------------------------
/public/assets/img/no_image.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/no_image.jpeg
--------------------------------------------------------------------------------
/public/assets/img/no_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/assets/img/no_image.png
--------------------------------------------------------------------------------
/public/assets/js/plugin/clusterize/clusterize.min.css:
--------------------------------------------------------------------------------
1 | .clusterize-scroll{max-height:50vh;overflow:auto;margin-right:-15px;margin-left:-15px}.clusterize-scroll::-webkit-scrollbar{width:6px;height:6px}.clusterize-scroll::-webkit-scrollbar-track{border-radius:10px;background:rgba(0,0,0,0.1)}.clusterize-scroll::-webkit-scrollbar-thumb{border-radius:10px;background:rgba(0,0,0,0.2)}.clusterize-scroll::-webkit-scrollbar-thumb:hover{background:rgba(0,0,0,0.4)}.clusterize-scroll::-webkit-scrollbar-thumb:active{background:rgba(0,0,0,0.9)}.clusterize-extra-row{margin-top:0!important;margin-bottom:0!important}.clusterize-extra-row.clusterize-keep-parity{display:none}.clusterize-header{font-weight:700;align-items:center;padding-right:6px}.clusterize-content{outline:0;counter-reset:clusterize-counter}.clusterize-content .row{margin-right:0;margin-left:0;align-items:center}.clusterize-content .row:hover{background-color:rgba(0,0,0,.075)!important}.clusterize-content .row:nth-of-type(odd){background:rgba(0,0,0,.025)}.clusterize-content [class^=col],.clusterize-header [class^=col]{padding-top:.3rem;padding-bottom:.3rem}.clusterize-no-data [class^=col]{text-align:center}
2 |
--------------------------------------------------------------------------------
/public/assets/js/plugin/codemirror/addon/dialog/dialog.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-dialog {
2 | position: absolute;
3 | left: 0; right: 0;
4 | background: inherit;
5 | z-index: 15;
6 | padding: .1em .8em;
7 | overflow: hidden;
8 | color: inherit;
9 | }
10 |
11 | .CodeMirror-dialog-top {
12 | border-bottom: 1px solid #eee;
13 | top: 0;
14 | }
15 |
16 | .CodeMirror-dialog-bottom {
17 | border-top: 1px solid #eee;
18 | bottom: 0;
19 | }
20 |
21 | .CodeMirror-dialog input {
22 | border: none;
23 | outline: none;
24 | background: transparent;
25 | width: 20em;
26 | color: inherit;
27 | font-family: monospace;
28 | }
29 |
30 | .CodeMirror-dialog button {
31 | font-size: 70%;
32 | }
33 |
--------------------------------------------------------------------------------
/public/assets/js/plugin/codemirror/addon/mode/multiplex_test.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function() {
5 | CodeMirror.defineMode("markdown_with_stex", function(){
6 | var inner = CodeMirror.getMode({}, "stex");
7 | var outer = CodeMirror.getMode({}, "markdown");
8 |
9 | var innerOptions = {
10 | open: '$',
11 | close: '$',
12 | mode: inner,
13 | delimStyle: 'delim',
14 | innerStyle: 'inner'
15 | };
16 |
17 | return CodeMirror.multiplexingMode(outer, innerOptions);
18 | });
19 |
20 | var mode = CodeMirror.getMode({}, "markdown_with_stex");
21 |
22 | function MT(name) {
23 | test.mode(
24 | name,
25 | mode,
26 | Array.prototype.slice.call(arguments, 1),
27 | 'multiplexing');
28 | }
29 |
30 | MT(
31 | "stexInsideMarkdown",
32 | "[strong **Equation:**] [delim&delim-open $][inner&tag \\pi][delim&delim-close $]");
33 | })();
34 |
--------------------------------------------------------------------------------
/public/assets/js/plugin/codemirror/mode/css/gss_test.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function() {
5 | "use strict";
6 |
7 | var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-gss");
8 | function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "gss"); }
9 |
10 | MT("atComponent",
11 | "[def @component] {",
12 | "[tag foo] {",
13 | " [property color]: [keyword black];",
14 | "}",
15 | "}");
16 |
17 | })();
18 |
--------------------------------------------------------------------------------
/public/assets/js/plugin/codemirror/mode/twig/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
CodeMirror: Twig mode
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
24 |
25 |
26 | Twig mode
27 |
40 |
45 |
46 |
--------------------------------------------------------------------------------
/public/assets/js/plugin/jquery-ui-touch-punch/jquery.ui.touch-punch.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery UI Touch Punch 0.2.3
3 | *
4 | * Copyright 2011–2014, Dave Furfero
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | *
7 | * Depends:
8 | * jquery.ui.widget.js
9 | * jquery.ui.mouse.js
10 | */
11 | "use strict";!function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);
--------------------------------------------------------------------------------
/public/index.php:
--------------------------------------------------------------------------------
1 | get('settings');
35 | $displayErrorDetails = $settings['displayErrorDetails'];
36 | $logError = $settings['logError'];
37 | $logErrorDetails = $settings['logErrorDetails'];
38 | $logger = $container->get(\Psr\Log\LoggerInterface::class);
39 |
40 | $app->add(\Slim\Views\TwigMiddleware::createFromContainer($app));
41 | $app->addRoutingMiddleware();
42 | $app->addErrorMiddleware($displayErrorDetails, $logError, $logErrorDetails, $logger);
43 | $app->run();
44 |
45 | // And nothing more :)
46 |
--------------------------------------------------------------------------------
/public/resource/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/resource/.gitkeep
--------------------------------------------------------------------------------
/public/uploads/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/public/uploads/.gitkeep
--------------------------------------------------------------------------------
/scheme/migrations/20240702092036.php:
--------------------------------------------------------------------------------
1 | table('user');
13 | $table
14 | ->addColumn('loyalty', 'text', ['default' => '[]', 'after' => 'source'])
15 | ->update();
16 | }
17 |
18 | public function down(): void
19 | {
20 | // revert user loyalty field
21 | $table = $this->table('user');
22 | $table
23 | ->removeColumn('loyalty')
24 | ->update();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/scheme/migrations/20240702092511.php:
--------------------------------------------------------------------------------
1 | []
12 | $table = $this->table('user_group');
13 | $table
14 | ->changeColumn('access', 'text', ['default' => '[]'])
15 | ->update();
16 | }
17 |
18 | public function down(): void
19 | {
20 | // revert user_group default value [] => {}
21 | $table = $this->table('user_group');
22 | $table
23 | ->changeColumn('access', 'text', ['default' => '{}'])
24 | ->update();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/scheme/migrations/20240727135000.php:
--------------------------------------------------------------------------------
1 | table('file');
13 | $table
14 | ->removeColumn('private')
15 | ->update();
16 | }
17 |
18 | public function down(): void
19 | {
20 | // revert file private field
21 | $table = $this->table('file');
22 | $table
23 | ->addColumn('private', 'boolean', ['default' => 0])
24 | ->update();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/scheme/migrations/20240807113500.php:
--------------------------------------------------------------------------------
1 | table('reference');
13 | $table->removeIndex('title')->save();
14 | $table->removeIndex('type')->save();
15 | $table->addIndex(['type', 'title'], ['unique' => true])->save();
16 | }
17 |
18 | public function down(): void
19 | {
20 | // remove new index
21 | $table = $this->table('reference');
22 | $table
23 | ->removeIndex(['type', 'title'], ['unique' => true])
24 | ->save();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/scheme/migrations/20240807122500.php:
--------------------------------------------------------------------------------
1 | table('user');
13 | $table->removeIndex('username')->save();
14 | $table->removeIndex('email')->save();
15 | $table->removeIndex('phone')->save();
16 | $table->addIndex(['username', 'email', 'phone'], ['unique' => true])->save();
17 | }
18 |
19 | public function down(): void
20 | {
21 | // remove new index
22 | $table = $this->table('user');
23 | $table
24 | ->removeIndex(['username', 'email', 'phone'])
25 | ->save();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/scheme/migrations/20250226101251.php:
--------------------------------------------------------------------------------
1 | table('params');
15 | $table->changeColumn('value', 'text', ['null' => false, 'default' => ''])
16 | ->update();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Application/Actions/Api/ActionApi.php:
--------------------------------------------------------------------------------
1 | respondWithText($this->getPublicKey());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Application/Actions/Auth/AuthAction.php:
--------------------------------------------------------------------------------
1 | auth = $container->get(Auth::class);
18 | }
19 |
20 | protected function isRequestJson(): bool
21 | {
22 | $headerAccept = $this->request->getHeaderLine('accept');
23 |
24 | return str_contains($headerAccept, 'application/json') || $headerAccept === '*/*';
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Application/Actions/Auth/LogoutAction.php:
--------------------------------------------------------------------------------
1 | getParam('redirect', '/');
10 | $refresh_token = $this->getParam('token', $this->getCookie('refresh_token', null));
11 |
12 | if ($refresh_token) {
13 | $this->auth->logout(
14 | $this->getParam('provider', $_SESSION['auth_provider'] ?? 'BasicAuthProvider'),
15 | $refresh_token,
16 | );
17 |
18 | @setcookie('access_token', '', time(), '/');
19 | @setcookie('refresh_token', '', time(), '/auth');
20 | }
21 |
22 | switch ($this->isRequestJson()) {
23 | case true:
24 | return $this->respondWithJson();
25 |
26 | case false:
27 | default:
28 | return $this->response->withAddedHeader('Location', $redirect)->withStatus(307);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Application/Actions/Auth/RevokeTokenAction.php:
--------------------------------------------------------------------------------
1 | getParam('redirect', '/');
12 | $refresh_token = $this->getParam('token', $this->getCookie('refresh_token'));
13 | $uuid = $this->getParam('uuid');
14 |
15 | if ($refresh_token) {
16 | $this->auth->revoke(
17 | $this->getParam('provider', $_SESSION['auth_provider'] ?? 'BasicAuthProvider'),
18 | $refresh_token,
19 | $uuid
20 | );
21 |
22 | /** @var User $user */
23 | if (($user = $this->request->getAttribute('user', false)) !== false && $user->tokens->isEmpty()) {
24 | $redirect = '/auth/logout';
25 | }
26 | }
27 |
28 | switch ($this->isRequestJson()) {
29 | case true:
30 | return $this->respondWithJson();
31 |
32 | case false:
33 | default:
34 | return $this->response->withAddedHeader('Location', $redirect)->withStatus(307);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Application/Actions/Common/Catalog/CartDoneAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('order') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('order'))) {
15 | try {
16 | $order = $this->catalogOrderService->read(['uuid' => $this->resolveArg('order')]);
17 |
18 | if ($order) {
19 | return $this
20 | ->respond($this->parameter('catalog_cart_complete_template', 'catalog.cart.complete.twig'), [
21 | 'order' => $order,
22 | ])
23 | ->withAddedHeader('X-Robots-Tag', 'noindex, nofollow');
24 | }
25 | } catch (OrderNotFoundException $e) {
26 | return $this->respond('p404.twig')->withStatus(404);
27 | }
28 | }
29 |
30 | return $this->respondWithRedirect('/cart');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Application/Actions/Common/Catalog/CatalogAction.php:
--------------------------------------------------------------------------------
1 | userService = $container->get(UserService::class);
30 | $this->catalogCategoryService = $container->get(CatalogCategoryService::class);
31 | $this->catalogProductService = $container->get(CatalogProductService::class);
32 | $this->catalogOrderService = $container->get(CatalogOrderService::class);
33 | $this->referenceService = $container->get(ReferenceService::class);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Application/Actions/Common/File/FileAction.php:
--------------------------------------------------------------------------------
1 | fileService = $container->get(FileService::class);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Application/Actions/Common/File/FileGetAction.php:
--------------------------------------------------------------------------------
1 | fileService->read([
11 | 'salt' => $this->resolveArg('salt'),
12 | 'hash' => $this->resolveArg('hash'),
13 | ]);
14 |
15 | return $this->response
16 | ->withHeader('Content-Type', 'application/download')
17 | ->withHeader('Content-Description', 'File Transfer')
18 | ->withHeader('Content-Transfer-Encoding', 'binary')
19 | ->withHeader('Content-Disposition', 'attachment; filename="' . $file->filename() . '"')
20 | ->withHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
21 | ->withHeader('Pragma', 'private')
22 | ->withHeader('Expires', '0')
23 | ->withBody(new \Slim\Psr7\Stream($file->resource()));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Application/Actions/Common/File/FileUploadAction.php:
--------------------------------------------------------------------------------
1 | getUploadedFiles(array_key_first($_FILES));
10 | $path_only = $this->getParam('path_only', false);
11 |
12 | if ($models && $path_only) {
13 | $file = array_shift($models)[0] ?? false;
14 |
15 | if ($file) {
16 | /** @var \App\Domain\Models\File $file */
17 | return $this->respondWithJson(['link' => $file->public_path()]);
18 | }
19 | }
20 |
21 | return $this->respondWithJson($models);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Application/Actions/Common/File/FileViewAction.php:
--------------------------------------------------------------------------------
1 | fileService->read([
11 | 'salt' => $this->resolveArg('salt'),
12 | 'hash' => $this->resolveArg('hash'),
13 | ]);
14 |
15 | return $this->response
16 | ->withHeader('Content-Type', $file->type)
17 | ->withHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
18 | ->withHeader('Pragma', 'private')
19 | ->withHeader('Expires', '0')
20 | ->withBody(new \Slim\Psr7\Stream($file->resource()));
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Application/Actions/Common/ForbiddenPageAction.php:
--------------------------------------------------------------------------------
1 | respond('p403.twig')->withStatus(403);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Application/Actions/Common/MainPageAction.php:
--------------------------------------------------------------------------------
1 | respond($this->parameter('common_template', 'main.twig'));
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Application/Actions/Common/PageAction.php:
--------------------------------------------------------------------------------
1 | container->get(PageService::class);
15 |
16 | try {
17 | $page = $pageService->read(['address' => ltrim($this->resolveArg('args'), '/')]);
18 |
19 | return $this->respond($page->template, [
20 | 'page' => $page,
21 | ]);
22 | } catch (HttpBadRequestException $e) {
23 | return $this->respond('p400.twig')->withStatus(400);
24 | } catch (PageNotFoundException $e) {
25 | return $this->respond('p404.twig')->withStatus(404);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Application/Actions/Common/User/UserAction.php:
--------------------------------------------------------------------------------
1 | auth = $container->get(Auth::class);
24 | $this->userService = $container->get(UserService::class);
25 | $this->userSubscriberService = $container->get(UserSubscriberService::class);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Application/Actions/Common/User/UserLogoutAction.php:
--------------------------------------------------------------------------------
1 | respondWithRedirect('/auth/logout');
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Application/Actions/Common/User/UserRevokeTokenAction.php:
--------------------------------------------------------------------------------
1 | $this->getParam('redirect', '/user/profile'),
11 | 'uuid' => $this->getParam('uuid'),
12 | ];
13 |
14 | return $this->respondWithRedirect('/auth/revoke?' . urldecode(http_build_query($params)));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Application/Actions/Common/XMLFileAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('name');
12 | $path = VAR_DIR . '/xml/' . $name . '.xml';
13 |
14 | if (file_exists($path)) {
15 | $this->response->getBody()->write(file_get_contents(VAR_DIR . '/xml/' . $name . '.xml'));
16 |
17 | return $this->response->withAddedHeader('Content-type', 'text/xml; charset=utf-8');
18 | }
19 |
20 | return $this->respond('p404.twig')->withStatus(404);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Catalog/Attribute/AttributeDeleteAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('attribute') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('attribute'))) {
13 | try {
14 | $attribute = $this->catalogAttributeService->read([
15 | 'uuid' => $this->resolveArg('attribute'),
16 | ]);
17 |
18 | if ($attribute) {
19 | $this->catalogAttributeService->delete($attribute);
20 |
21 | $this->container->get(\App\Application\PubSub::class)->publish('cup:catalog:attribute:delete', $attribute);
22 | }
23 | } catch (AttributeNotFoundException $e) {
24 | // nothing
25 | }
26 | }
27 |
28 | return $this->respondWithRedirect('/cup/catalog/attribute');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Catalog/Attribute/AttributeListAction.php:
--------------------------------------------------------------------------------
1 | catalogAttributeService->read([
12 | 'order' => [
13 | 'group' => 'asc',
14 | 'title' => 'asc',
15 | ],
16 | ]);
17 |
18 | return $this->respondWithTemplate('cup/catalog/attribute/index.twig', [
19 | 'attributes' => $list,
20 | ]);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Catalog/Category/CategoryListAction.php:
--------------------------------------------------------------------------------
1 | catalogCategoryService->read([
12 | 'status' => \App\Domain\Casts\Catalog\Status::WORK,
13 | 'order' => [
14 | 'order' => 'ASC',
15 | 'title' => 'ASC',
16 | ],
17 | ]);
18 |
19 | return $this->respondWithTemplate('cup/catalog/category/index.twig', [
20 | 'categories' => $categories,
21 | ]);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Catalog/Order/OrderDeleteAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('order') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('order'))) {
13 | try {
14 | $order = $this->catalogOrderService->read([
15 | 'uuid' => $this->resolveArg('order'),
16 | ]);
17 |
18 | if ($order) {
19 | $this->catalogOrderService->delete($order);
20 |
21 | $this->container->get(\App\Application\PubSub::class)->publish('cup:catalog:order:delete', $order);
22 | }
23 | } catch (OrderNotFoundException $e) {
24 | // nothing
25 | }
26 | }
27 |
28 | return $this->respondWithRedirect('/cup/catalog/order');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Catalog/Order/OrderDispatchAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('order') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('order'))) {
12 | $order = $this->catalogOrderService->read(['uuid' => $this->resolveArg('order')]);
13 |
14 | if ($order) {
15 | return $this->respondWithTemplate('cup/catalog/order/dispatch.twig', [
16 | 'order' => $order,
17 | 'template' => $this->parameter('catalog_dispatch', ''),
18 | ]);
19 | }
20 | }
21 |
22 | return $this->respondWithRedirect('/cup/catalog/order');
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Catalog/Order/OrderDocumentAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('order') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('order'))
13 | && $this->resolveArg('uuid') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('uuid'))
14 | ) {
15 | $order = $this->catalogOrderService->read(['uuid' => $this->resolveArg('order')]);
16 |
17 | if ($order) {
18 | $document = $this->referenceService->read(['uuid' => $this->resolveArg('uuid')]);
19 |
20 | return $this->respondWithTemplate('cup/catalog/order/document-view.twig', [
21 | 'order' => $order,
22 | 'document' => $document,
23 | 'template' => $document->value['template'] ?? '',
24 | ]);
25 | }
26 | }
27 |
28 | return $this->respondWithRedirect('/cup/catalog/order');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Catalog/Product/ProductDeleteAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('product') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('product'))) {
15 | try {
16 | $product = $this->catalogProductService->read([
17 | 'uuid' => $this->resolveArg('product'),
18 | 'status' => \App\Domain\Casts\Catalog\Status::WORK,
19 | ]);
20 |
21 | if ($product) {
22 | $this->catalogProductService->update($product, [
23 | 'status' => \App\Domain\Casts\Catalog\Status::DELETE,
24 | ]);
25 |
26 | $this->container->get(\App\Application\PubSub::class)->publish('cup:catalog:product:delete', $product);
27 | }
28 |
29 | return $this->respondWithRedirect('/cup/catalog/product' . ($product ? '/' . $product->category->uuid : ''));
30 | } catch (ProductNotFoundException $e) {
31 | // nothing
32 | }
33 | }
34 |
35 | return $this->respondWithRedirect('/cup/catalog/product');
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Catalog/Product/ProductImportAction.php:
--------------------------------------------------------------------------------
1 | isPost()) {
12 | // Fields
13 | $fields = array_map('trim', explode(PHP_EOL, $this->parameter('catalog_import_columns', '')));
14 |
15 | if ($fields) {
16 | /** @var \App\Domain\Models\File $file */
17 | $file = array_first($this->getUploadedFiles('excel', 0));
18 |
19 | if ($file) {
20 | // add import task
21 | $task = new \App\Domain\Tasks\Catalog\ProductImportTask($this->container);
22 | $task->execute([
23 | 'fields' => $fields, // todo check is later
24 | 'file' => $file->uuid,
25 | ]);
26 |
27 | // run worker
28 | \App\Domain\AbstractTask::worker($task);
29 | }
30 | }
31 | }
32 |
33 | return $this->response->withAddedHeader('Location', $_SERVER['HTTP_REFERER'] ?? '/cup/catalog/product')->withStatus(301);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/File/FileAction.php:
--------------------------------------------------------------------------------
1 | fileService = $container->get(FileService::class);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/File/FileDeleteAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('uuid') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('uuid'))) {
12 | try {
13 | $file = $this->fileService->read([
14 | 'uuid' => $this->resolveArg('uuid'),
15 | ]);
16 |
17 | if ($file) {
18 | $this->fileService->delete($file);
19 |
20 | $this->container->get(\App\Application\PubSub::class)->publish('cup:file:delete', $file);
21 | }
22 | } catch (FileNotFoundException $e) {
23 | // nothing
24 | }
25 | }
26 |
27 | return $this->respondWithRedirect('/cup/file');
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/File/FileListAction.php:
--------------------------------------------------------------------------------
1 | respondWithTemplate('cup/file/index.twig', [
10 | 'list' => $this->fileService->read(['order' => ['date' => 'desc']]),
11 | ]);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/File/Image/DeleteAction.php:
--------------------------------------------------------------------------------
1 | getParam('src', false);
13 |
14 | if ($src !== false) {
15 | $info = pathinfo($src);
16 |
17 | try {
18 | $file = $this->fileService->read([
19 | 'name' => str_escape($info['filename']),
20 | 'ext' => str_escape($info['extension']),
21 | ]);
22 |
23 | if ($file) {
24 | $this->fileService->delete($file);
25 |
26 | $this->container->get(\App\Application\PubSub::class)->publish('cup:file:delete', $file);
27 | }
28 |
29 | return $this->respondWithJson(['status' => 'ok']);
30 | } catch (FileNotFoundException $e) {
31 | // nothing
32 | }
33 | }
34 |
35 | return $this->respondWithJson(['status' => 'not found']);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/File/Image/GetAction.php:
--------------------------------------------------------------------------------
1 | fileService->read() as $file) {
14 | /** @var \App\Domain\Models\File $file */
15 | if (str_starts_with($file->type, 'image/')) {
16 | $result[] = [
17 | 'url' => $file->public_path(),
18 | 'thumb' => $file->public_path('small'),
19 | ];
20 | }
21 | }
22 |
23 | return $this->respondWithJson($result);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/ForbiddenPageAction.php:
--------------------------------------------------------------------------------
1 | respondWithTemplate('cup/auth/forbidden.twig')->withStatus(403);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Form/Data/DataDeleteAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('uuid') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('uuid'))
14 | && $this->resolveArg('data') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('data'))
15 | ) {
16 | try {
17 | $data = $this->formDataService->read([
18 | 'uuid' => $this->resolveArg('data'),
19 | ]);
20 |
21 | if ($data) {
22 | $this->formDataService->delete($data);
23 |
24 | $this->container->get(\App\Application\PubSub::class)->publish('cup:form:data:delete', $data);
25 | }
26 | } catch (FormDataNotFoundException $e) {
27 | // nothing
28 | }
29 | }
30 |
31 | return $this->respondWithRedirect('/cup/form/' . $this->resolveArg('uuid') . '/view');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Form/Data/DataListAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('uuid') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('uuid'))) {
12 | $form = $this->formService->read(['uuid' => $this->resolveArg('uuid')]);
13 |
14 | if ($form) {
15 | $list = $this->formDataService->read([
16 | 'form_uuid' => $form->uuid,
17 | 'order' => [
18 | 'date' => 'desc',
19 | ],
20 | ]);
21 |
22 | return $this->respondWithTemplate('cup/form/view/list.twig', [
23 | 'form' => $form,
24 | 'list' => $list,
25 | ]);
26 | }
27 | }
28 |
29 | return $this->respondWithRedirect('/cup/form');
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Form/Data/DataViewAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('uuid') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('uuid'))
13 | && $this->resolveArg('data') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('data'))
14 | ) {
15 | $data = $this->formDataService->read([
16 | 'uuid' => $this->resolveArg('data'),
17 | ]);
18 |
19 | if ($data) {
20 | return $this->respondWithTemplate('cup/form/view/detail.twig', [
21 | 'item' => $data,
22 | ]);
23 | }
24 | }
25 |
26 | return $this->respondWithRedirect('/cup/form');
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Form/FormAction.php:
--------------------------------------------------------------------------------
1 | formService = $container->get(FormService::class);
21 | $this->formDataService = $container->get(FormDataService::class);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Form/FormDeleteAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('uuid') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('uuid'))) {
12 | try {
13 | $form = $this->formService->read([
14 | 'uuid' => $this->resolveArg('uuid'),
15 | ]);
16 |
17 | if ($form) {
18 | foreach ($this->formDataService->read(['form_uuid' => $this->resolveArg('uuid')]) as $item) {
19 | $this->formDataService->delete($item);
20 | }
21 |
22 | $this->formService->delete($form);
23 |
24 | $this->container->get(\App\Application\PubSub::class)->publish('cup:form:delete', $form);
25 | }
26 | } catch (FormNotFoundException $e) {
27 | // nothing
28 | }
29 | }
30 |
31 | return $this->respondWithRedirect('/cup/form');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Form/FormListAction.php:
--------------------------------------------------------------------------------
1 | respondWithTemplate('cup/form/index.twig', [
10 | 'list' => $this->formService->read(['order' => ['title' => 'asc']]),
11 | ]);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/GuestBook/GuestBookAction.php:
--------------------------------------------------------------------------------
1 | guestBookService = $container->get(GuestBookService::class);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/GuestBook/GuestBookDeleteAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('uuid') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('uuid'))) {
12 | try {
13 | $entry = $this->guestBookService->read([
14 | 'uuid' => $this->resolveArg('uuid'),
15 | ]);
16 |
17 | if ($entry) {
18 | $this->guestBookService->delete($entry);
19 |
20 | $this->container->get(\App\Application\PubSub::class)->publish('cup:guestbook:delete', $entry);
21 | }
22 | } catch (EntryNotFoundException $e) {
23 | // nothing
24 | }
25 | }
26 |
27 | return $this->respondWithRedirect('/cup/guestbook');
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/GuestBook/GuestBookListAction.php:
--------------------------------------------------------------------------------
1 | respondWithTemplate('cup/guestbook/index.twig', [
10 | 'list' => $this->guestBookService->read(['order' => ['date' => 'desc']]),
11 | ]);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/LogPageAction.php:
--------------------------------------------------------------------------------
1 | getFileContents($path);
16 | }
17 | }
18 |
19 | return $this->respondWithTemplate('cup/logs.twig', [
20 | 'files' => array_reverse($files),
21 | ]);
22 | }
23 |
24 | private function getFileContents($path, $lines = 1000): string
25 | {
26 | $file = file($path);
27 |
28 | return implode(PHP_EOL, array_map('trim', array_slice($file, 0 - $lines)));
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Page/PageAction.php:
--------------------------------------------------------------------------------
1 | pageService = $container->get(PageService::class);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Page/PageDeleteAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('uuid') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('uuid'))) {
12 | try {
13 | $page = $this->pageService->read([
14 | 'uuid' => $this->resolveArg('uuid'),
15 | ]);
16 |
17 | if ($page) {
18 | $this->pageService->delete($page);
19 |
20 | $this->container->get(\App\Application\PubSub::class)->publish('cup:page:delete', $page);
21 | }
22 | } catch (PageNotFoundException $e) {
23 | // nothing
24 | }
25 | }
26 |
27 | return $this->respondWithRedirect('/cup/page');
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Page/PageListAction.php:
--------------------------------------------------------------------------------
1 | respondWithTemplate('cup/page/index.twig', [
10 | 'list' => $this->pageService->read(['order' => ['title' => 'asc']]),
11 | ]);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Publication/Category/CategoryListAction.php:
--------------------------------------------------------------------------------
1 | respondWithTemplate('cup/publication/category/index.twig', [
12 | 'categories' => $this->publicationCategoryService->read(['order' => ['title' => 'asc']]),
13 | ]);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Publication/PublicationAction.php:
--------------------------------------------------------------------------------
1 | publicationCategoryService = $container->get(PublicationCategoryService::class);
21 | $this->publicationService = $container->get(PublicationService::class);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Publication/PublicationDeleteAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('uuid') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('uuid'))) {
12 | try {
13 | $publication = $this->publicationService->read([
14 | 'uuid' => $this->resolveArg('uuid'),
15 | ]);
16 |
17 | if ($publication) {
18 | $this->publicationService->delete($publication);
19 |
20 | $this->container->get(\App\Application\PubSub::class)->publish('cup:publication:delete', $publication);
21 | }
22 | } catch (PublicationNotFoundException $e) {
23 | // nothing
24 | }
25 | }
26 |
27 | return $this->response->withAddedHeader('Location', '/cup/publication')->withStatus(301);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Publication/PublicationListAction.php:
--------------------------------------------------------------------------------
1 | respondWithTemplate('cup/publication/index.twig', [
10 | 'categories' => $this->publicationCategoryService->read(),
11 | 'publications' => $this->publicationService->read(['order' => ['date' => 'desc']]),
12 | ]);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Publication/PublicationPreviewAction.php:
--------------------------------------------------------------------------------
1 | respondWithTemplate('cup/publication/preview.twig');
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Reference/ReferenceDeleteAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('uuid') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('uuid'))) {
12 | try {
13 | $reference = $this->referenceService->read([
14 | 'uuid' => $this->resolveArg('uuid'),
15 | ]);
16 | $this->referenceService->delete($reference);
17 |
18 | $this->container->get(\App\Application\PubSub::class)->publish('cup:reference:delete', $reference);
19 | } catch (ReferenceNotFoundException $e) {
20 | // nothing
21 | }
22 | }
23 |
24 | return $this->respondWithRedirect($_SERVER['HTTP_REFERER']);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/Reference/ReferenceListAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('entity');
10 |
11 | return $this->respondWithTemplate("cup/reference/{$entity}/index.twig", [
12 | 'list' => $this->referenceService->read([
13 | 'type' => $this->resolveReferenceType($entity),
14 | ]),
15 | ]);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/TaskRunAction.php:
--------------------------------------------------------------------------------
1 | request->getHeaderLine('Referer') ?? '/cup';
12 |
13 | if ($this->isPost()) {
14 | if (($name = $this->getParam('task', null)) !== null && class_exists($name)) {
15 | /** @var \App\Domain\AbstractTask $task */
16 | $task = new $name($this->container);
17 | $task->execute($this->getParam('params', []));
18 |
19 | // run worker
20 | \App\Domain\AbstractTask::worker($task);
21 |
22 | $this->container->get(\App\Application\PubSub::class)->publish('cup:task:run', $task);
23 |
24 | $this->response = $this->response->withAddedHeader('Location', $redirect)->withStatus(301);
25 | }
26 | }
27 |
28 | return $this->respondWithJson(['run' => time()]);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/User/Group/DeleteAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('uuid') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('uuid'))) {
13 | try {
14 | $userGroup = $this->userGroupService->read([
15 | 'uuid' => $this->resolveArg('uuid'),
16 | ]);
17 |
18 | if ($userGroup) {
19 | $this->userGroupService->delete($userGroup);
20 |
21 | $this->container->get(\App\Application\PubSub::class)->publish('cup:user:group:delete', $userGroup);
22 | }
23 | } catch (UserGroupNotFoundException $e) {
24 | // nothing
25 | }
26 | }
27 |
28 | return $this->respondWithRedirect('/cup/user/group');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/User/Group/ListAction.php:
--------------------------------------------------------------------------------
1 | respondWithTemplate('cup/user/group/index.twig', [
12 | 'groups' => $this->userGroupService->read(['order' => ['title' => 'asc']]),
13 | 'users' => $this->userService->read(['status' => \App\Domain\Casts\User\Status::WORK]),
14 | ]);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/User/NewsLetter/CreateAction.php:
--------------------------------------------------------------------------------
1 | isPost()) {
12 | $task = new \App\Domain\Tasks\SendNewsLetterMailTask($this->container);
13 | $task->execute([
14 | 'subject' => $this->getParam('subject'),
15 | 'body' => $this->getParam('body'),
16 | 'type' => $this->getParam('type'),
17 | ]);
18 |
19 | // run worker
20 | \App\Domain\AbstractTask::worker($task);
21 |
22 | return $this->respondWithRedirect('/cup/user/newsletter');
23 | }
24 |
25 | return $this->respondWithTemplate('cup/user/newsletter/form.twig');
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/User/Subscriber/CreateAction.php:
--------------------------------------------------------------------------------
1 | isPost()) {
14 | try {
15 | $this->userSubscriberService->create([
16 | 'email' => $this->getParam('email'),
17 | ]);
18 | } catch (EmailAlreadyExistsException|WrongEmailValueException $e) {
19 | $this->addError('email', $e->getMessage());
20 | }
21 | }
22 |
23 | return $this->respondWithRedirect('/cup/user/subscriber');
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/User/Subscriber/DeleteAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('uuid') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('uuid'))) {
13 | try {
14 | $userSubscriber = $this->userSubscriberService->read(['uuid' => $this->resolveArg('uuid')]);
15 |
16 | if ($userSubscriber) {
17 | $this->userSubscriberService->delete($userSubscriber);
18 | }
19 | } catch (UserNotFoundException $e) {
20 | // nothing
21 | }
22 | }
23 |
24 | return $this->respondWithRedirect('/cup/user/subscriber');
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/User/Subscriber/ListAction.php:
--------------------------------------------------------------------------------
1 | respondWithTemplate('cup/user/subscriber/index.twig', [
12 | 'list' => $this->userSubscriberService->read(['order' => ['date' => 'desc']]),
13 | ]);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/User/UserAction.php:
--------------------------------------------------------------------------------
1 | userService = $container->get(UserService::class);
24 | $this->userGroupService = $container->get(UserGroupService::class);
25 | $this->userSubscriberService = $container->get(UserSubscriberService::class);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/User/UserDeleteAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('uuid') && \Ramsey\Uuid\Uuid::isValid($this->resolveArg('uuid'))) {
12 | try {
13 | $user = $this->userService->read([
14 | 'uuid' => $this->resolveArg('uuid'),
15 | ]);
16 |
17 | if ($user) {
18 | $this->userService->delete($user);
19 |
20 | $this->container->get(\App\Application\PubSub::class)->publish('cup:user:delete', $user);
21 | }
22 | } catch (UserNotFoundException $e) {
23 | // nothing
24 | }
25 | }
26 |
27 | return $this->response->withAddedHeader('Location', '/cup/user')->withStatus(301);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Application/Actions/Cup/User/UserViewAction.php:
--------------------------------------------------------------------------------
1 | resolveArg('uuid')) {
10 | $user = $this->userService->read(['uuid' => $this->resolveArg('uuid')]);
11 |
12 | if ($user) {
13 | return $this->respondWithTemplate('cup/user/view.twig', [
14 | 'item' => $user,
15 | ]);
16 | }
17 | }
18 |
19 | return $this->respondWithRedirect('/cup/user');
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Application/Mail.php:
--------------------------------------------------------------------------------
1 | '',
15 | 'mail_from_name' => '',
16 | 'subject' => 'WebSpaceEngine | Default subject',
17 | 'to' => '', // string|array(address=>name)
18 | 'cc' => '', // string|array(address=>name)
19 | 'bcc' => '', // string|array(address=>name)
20 | 'body' => '',
21 | 'isHtml' => false,
22 | 'attachments' => [],
23 |
24 | // sendpulse section
25 | 'sendpulse_is_enabled' => 'off',
26 | 'sendpulse_id' => '',
27 | 'sendpulse_secret' => '',
28 |
29 | // smtp section
30 | 'smtp_login' => '',
31 | 'smtp_pass' => '',
32 | 'smtp_secure' => '',
33 | 'smtp_host' => '',
34 | 'smtp_port' => '',
35 | 'smtp_timeout' => 30,
36 | 'smtp_options' => [],
37 | ];
38 | $data = array_merge($default, $data);
39 |
40 | return match (true) {
41 | $data['sendpulse_is_enabled'] && $data['sendpulse_id'] && $data['sendpulse_secret'] => SPProvider::send($data),
42 | default => SMTPProvider::send($data),
43 | };
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Application/Mail/MailProviderInterface.php:
--------------------------------------------------------------------------------
1 | handle($request);
17 |
18 | if (($value = $this->parameter('entity_cors_origin', false)) !== false) {
19 | $origin = $request->getHeaderLine('Origin');
20 |
21 | if ($origin && in_array($origin, explode(PHP_EOL, $value), true) || $value === '*') {
22 | $response = $response->withHeader('Access-Control-Allow-Origin', $origin);
23 | }
24 | }
25 | if (($value = $this->parameter('entity_cors_headers', false)) !== false) {
26 | $response = $response->withHeader('Access-Control-Allow-Headers', $value);
27 | }
28 | if (($value = $this->parameter('entity_cors_methods', false)) !== false) {
29 | $response = $response->withHeader('Access-Control-Allow-Methods', mb_strtoupper($value));
30 | }
31 |
32 | return $response;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Application/Middlewares/IsRouteEnabledAPIMiddleware.php:
--------------------------------------------------------------------------------
1 | getRoute();
20 | $routeName = explode(':', $route->getName())[2] ?? '';
21 |
22 | if ($routeName && $this->parameter($routeName . '_is_enabled', 'yes') !== 'no') {
23 | return $handler->handle($request);
24 | }
25 |
26 | $response = new Response();
27 | $response->getBody()->write('Access denied');
28 |
29 | return $response
30 | ->withHeader('Content-Type', 'text/plain; charset=utf-8')
31 | ->withStatus(423);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Application/Middlewares/IsRouteEnabledMiddleware.php:
--------------------------------------------------------------------------------
1 | getRoute();
20 | $routeName = explode(':', $route->getName())[1] ?? '';
21 |
22 | if ($routeName && $this->parameter($routeName . '_is_enabled', 'yes') !== 'no') {
23 | return $handler->handle($request);
24 | }
25 |
26 | return (new Response())
27 | ->withHeader('Location', str_starts_with($route->getPattern(), '/cup') ? '/cup/forbidden' : '/forbidden')
28 | ->withStatus(307);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Application/Middlewares/IsSiteEnabledMiddleware.php:
--------------------------------------------------------------------------------
1 | parameter('common_site_enabled', 'yes') !== 'yes') {
18 | $renderer = $this->container->get('view');
19 |
20 | if (($path = realpath(THEME_DIR . '/' . $this->parameter('common_theme', 'default'))) !== false) {
21 | $renderer->getLoader()->addPath($path);
22 | }
23 |
24 | // add default errors pages
25 | $renderer->getLoader()->addPath(VIEW_ERROR_DIR);
26 |
27 | $response = (new Response())->withStatus(503);
28 | $response->getBody()->write($renderer->fetch('p503.twig'));
29 |
30 | return $response;
31 | }
32 |
33 | return $handler->handle($request);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Application/Middlewares/LocaleMiddleware.php:
--------------------------------------------------------------------------------
1 | parameter('common_language', 'en-US');
19 | $user_locale = $request->getCookieParams()['language'] ?? null;
20 | $query_locale = $request->getQueryParams()['lang'] ?? null;
21 |
22 | // change lang by cookie
23 | if ($query_locale !== null) {
24 | $user_locale = $query_locale;
25 |
26 | @setcookie('language', $query_locale, time() + \App\Domain\References\Date::YEAR, '/');
27 | }
28 |
29 | // change lang by user settings
30 | if (!$user_locale && ($user = $request->getAttribute('user', false)) !== false) {
31 | /** @var User $user */
32 | if ($code = $user->language) {
33 | $user_locale = $code;
34 | }
35 | }
36 |
37 | i18n::init([
38 | 'locale' => i18n::getLanguageFromHeader($request->getHeaderLine('Accept-Language'), $default_locale),
39 | 'default' => $default_locale,
40 | 'force' => $user_locale,
41 | ]);
42 |
43 | return $handler->handle($request);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Application/Middlewares/NonWWWMiddleware.php:
--------------------------------------------------------------------------------
1 | parameter('common_non_www', 'no') === 'yes') {
18 | $scheme = $request->getUri()->getScheme();
19 | $host = $request->getUri()->getHost();
20 |
21 | if (str_starts_with($host, 'www')) {
22 | return (new Response())
23 | ->withHeader('Location', $scheme . '://' . str_replace('www.', '', $host))
24 | ->withStatus(308);
25 | }
26 | }
27 |
28 | return $handler->handle($request);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Domain/AbstractException.php:
--------------------------------------------------------------------------------
1 | message = $message;
15 | }
16 |
17 | parent::__construct($this->message, $this->code, $previous);
18 | }
19 |
20 | public function getTitle(): string
21 | {
22 | return $this->title ?: (new \ReflectionClass($this))->getShortName();
23 | }
24 |
25 | public function setTitle(string $title): self
26 | {
27 | $this->title = $title;
28 |
29 | return $this;
30 | }
31 |
32 | public function getDescription(): string
33 | {
34 | return $this->description ?: $this->getMessage();
35 | }
36 |
37 | public function setDescription(string $description): self
38 | {
39 | $this->description = $description;
40 |
41 | return $this;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Domain/AbstractExtension.php:
--------------------------------------------------------------------------------
1 | container = $container;
27 | $this->db = $container->get(DataBase::class);
28 | $this->arrayCache = $container->get(ArrayCache::class);
29 | $this->fileCache = $container->get(FileCache::class);
30 | }
31 |
32 | public function getTokenParsers()
33 | {
34 | return [];
35 | }
36 |
37 | public function getNodeVisitors()
38 | {
39 | return [];
40 | }
41 |
42 | public function getFilters()
43 | {
44 | return [];
45 | }
46 |
47 | public function getTests()
48 | {
49 | return [];
50 | }
51 |
52 | public function getFunctions()
53 | {
54 | return [];
55 | }
56 |
57 | public function getOperators()
58 | {
59 | return [];
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Domain/AbstractHttpException.php:
--------------------------------------------------------------------------------
1 | container = $container;
28 | $this->db = $container->get(DataBase::class);
29 | $this->arrayCache = $container->get(ArrayCache::class);
30 | $this->fileCache = $container->get(FileCache::class);
31 | }
32 |
33 | abstract public function __invoke(Request $request, RequestHandlerInterface $handler): \Slim\Psr7\Response;
34 |
35 | protected function getRequestRemoteIP(Request $request): string
36 | {
37 | return
38 | $request->getServerParams()['HTTP_X_REAL_IP'] ??
39 | $request->getServerParams()['HTTP_X_FORWARDED_FOR'] ??
40 | $request->getServerParams()['REMOTE_ADDR'] ??
41 | '';
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Domain/AbstractNotFoundException.php:
--------------------------------------------------------------------------------
1 | [],
25 | 'limit' => null,
26 | 'offset' => null,
27 | ];
28 |
29 | public function __construct(ContainerInterface $container)
30 | {
31 | $this->container = $container;
32 | $this->db = $container->get(DataBase::class);
33 | $this->arrayCache = $container->get(ArrayCache::class);
34 | $this->fileCache = $container->get(FileCache::class);
35 | }
36 |
37 | abstract public function create(array $data = []);
38 |
39 | abstract public function read(array $data = []);
40 |
41 | abstract public function update($entity, array $data = []);
42 |
43 | abstract public function delete($entity);
44 | }
45 |
--------------------------------------------------------------------------------
/src/Domain/Casts/AddressUrl.php:
--------------------------------------------------------------------------------
1 | title ?? '';
19 | }
20 |
21 | $value = mb_strtolower($value);
22 | $value = i18n::getTranslatedText($value);
23 | $value = trim($value);
24 | $value = preg_replace(['/[^\w\s\/-]/', '/\s+/'], ['', '-'], $value);
25 |
26 | return implode('/', array_unique(explode('/', $value))); // for fix duplicate parts
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Domain/Casts/Boolean.php:
--------------------------------------------------------------------------------
1 | '',
11 | 'address' => '',
12 | ];
13 |
14 | public function get($model, string $key, mixed $value, array $attributes): array
15 | {
16 | $value = json_decode($value, true);
17 |
18 | return array_merge($this->default, $value);
19 | }
20 |
21 | public function set($model, string $key, mixed $value, array $attributes): string
22 | {
23 | return json_encode(array_merge($this->default, $value), JSON_UNESCAPED_UNICODE);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Domain/Casts/Catalog/Product/Dimension.php:
--------------------------------------------------------------------------------
1 | 0.0,
11 | 'width' => 0.0,
12 | 'height' => 0.0,
13 | 'weight' => 0.0,
14 | 'length_class' => '',
15 | 'weight_class' => '',
16 | ];
17 |
18 | public function get($model, string $key, mixed $value, array $attributes): array
19 | {
20 | $value = json_decode($value, true);
21 |
22 | return array_merge($this->default, $value);
23 | }
24 |
25 | public function set($model, string $key, mixed $value, array $attributes): string
26 | {
27 | return json_encode(array_merge($this->default, $value), JSON_UNESCAPED_UNICODE);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Domain/Casts/Catalog/Product/Tags.php:
--------------------------------------------------------------------------------
1 | '',
11 | 'description' => '',
12 | 'keywords' => '',
13 | ];
14 |
15 | public function get($model, string $key, mixed $value, array $attributes): array
16 | {
17 | $value = json_decode($value, true);
18 |
19 | return array_merge($this->default, $value);
20 | }
21 |
22 | public function set($model, string $key, mixed $value, array $attributes): string
23 | {
24 | return json_encode(array_merge($this->default, $value), JSON_UNESCAPED_UNICODE);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Domain/Casts/Page/Type.php:
--------------------------------------------------------------------------------
1 | '',
11 | 'direction' => '',
12 | ];
13 |
14 | public function get($model, string $key, mixed $value, array $attributes): array
15 | {
16 | $value = json_decode($value, true);
17 |
18 | return array_merge($this->default, $value);
19 | }
20 |
21 | public function set($model, string $key, mixed $value, array $attributes): string
22 | {
23 | return json_encode(array_merge($this->default, $value), JSON_UNESCAPED_UNICODE);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Domain/Casts/Task/Status.php:
--------------------------------------------------------------------------------
1 | '',
11 | 'position' => '',
12 | ];
13 |
14 | public function get($model, string $key, mixed $value, array $attributes): array
15 | {
16 | $value = json_decode($value, true);
17 |
18 | return array_merge($this->default, $value);
19 | }
20 |
21 | public function set($model, string $key, mixed $value, array $attributes): string
22 | {
23 | if ($value) {
24 | return json_encode(array_merge($this->default, $value), JSON_UNESCAPED_UNICODE);
25 | }
26 |
27 | return '{}';
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Domain/Casts/User/Legal.php:
--------------------------------------------------------------------------------
1 | '',
11 | 'number' => '',
12 | ];
13 |
14 | public function get($model, string $key, mixed $value, array $attributes): array
15 | {
16 | $value = json_decode($value, true);
17 |
18 | return array_merge($this->default, $value);
19 | }
20 |
21 | public function set($model, string $key, mixed $value, array $attributes): string
22 | {
23 | if ($value) {
24 | return json_encode(array_merge($this->default, $value), JSON_UNESCAPED_UNICODE);
25 | }
26 |
27 | return '{}';
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Domain/Casts/User/Messenger.php:
--------------------------------------------------------------------------------
1 | '',
11 | 'telegram' => '',
12 | 'whatsapp' => '',
13 | 'viber' => '',
14 | 'facebook' => '',
15 | 'instagram' => '',
16 | 'signal' => '',
17 | ];
18 |
19 | public function get($model, string $key, mixed $value, array $attributes): array
20 | {
21 | $value = json_decode($value, true);
22 |
23 | return array_merge($this->default, $value);
24 | }
25 |
26 | public function set($model, string $key, mixed $value, array $attributes): string
27 | {
28 | if ($value) {
29 | return json_encode(array_merge($this->default, $value), JSON_UNESCAPED_UNICODE);
30 | }
31 |
32 | return '{}';
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Domain/Casts/User/Password.php:
--------------------------------------------------------------------------------
1 | password;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Domain/Casts/User/Status.php:
--------------------------------------------------------------------------------
1 | url = $url;
22 |
23 | parent::__construct($this->message, $previous);
24 | }
25 |
26 | public function getUrl(): string
27 | {
28 | return $this->url;
29 | }
30 |
31 | public function setUrl(string $url): self
32 | {
33 | $this->url = $url;
34 |
35 | return $this;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Domain/Exceptions/JWTExpiredException.php:
--------------------------------------------------------------------------------
1 | Uuid::class,
43 | 'data' => Json::class,
44 | 'message' => 'string',
45 | 'date' => 'datetime',
46 | ];
47 |
48 | protected $attributes = [
49 | 'form_uuid' => '',
50 | 'data' => '{}',
51 | 'message' => '',
52 | 'date' => 'now',
53 | ];
54 |
55 | public function form(): HasOne
56 | {
57 | return $this->hasOne(Form::class, 'uuid', 'form_uuid');
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Domain/Models/GuestBook.php:
--------------------------------------------------------------------------------
1 | 'string',
43 | 'email' => Email::class,
44 | 'message' => 'string',
45 | 'response' => 'string',
46 | 'status' => GuestBookStatus::class,
47 | 'date' => 'datetime',
48 | ];
49 |
50 | protected $attributes = [
51 | 'name' => '',
52 | 'email' => '',
53 | 'message' => '',
54 | 'response' => '',
55 | 'status' => \App\Domain\Casts\GuestBook\Status::MODERATE,
56 | 'date' => 'now',
57 | ];
58 | }
59 |
--------------------------------------------------------------------------------
/src/Domain/Models/Parameter.php:
--------------------------------------------------------------------------------
1 | 'string',
31 | 'value' => 'string',
32 | ];
33 |
34 | protected $attributes = [
35 | 'name' => '',
36 | 'value' => '',
37 | ];
38 | }
39 |
--------------------------------------------------------------------------------
/src/Domain/Models/Reference.php:
--------------------------------------------------------------------------------
1 | ReferenceType::class,
42 | 'title' => 'string',
43 | 'value' => Json::class,
44 | 'order' => 'int',
45 | 'status' => Boolean::class,
46 | ];
47 |
48 | protected $attributes = [
49 | 'type' => '',
50 | 'title' => '',
51 | 'value' => '{}',
52 | 'order' => 1,
53 | 'status' => true,
54 | ];
55 |
56 | public function value(?string $key = null, mixed $default = null): mixed
57 | {
58 | if ($key) {
59 | return $this->value[$key] ?? $default;
60 | }
61 |
62 | return $this->value;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Domain/Models/Task.php:
--------------------------------------------------------------------------------
1 | 'string',
46 | 'action' => 'string',
47 | 'progress' => Decimal::class,
48 | 'status' => TaskStatus::class,
49 | 'params' => Json::class,
50 | 'output' => 'string',
51 | 'date' => 'datetime',
52 | ];
53 |
54 | protected $attributes = [
55 | 'title' => '',
56 | 'action' => '',
57 | 'progress' => .00,
58 | 'status' => \App\Domain\Casts\Task\Status::QUEUE,
59 | 'params' => '{}',
60 | 'output' => '',
61 | 'date' => 'now',
62 | ];
63 | }
64 |
--------------------------------------------------------------------------------
/src/Domain/Models/UserGroup.php:
--------------------------------------------------------------------------------
1 | $users
18 | */
19 | class UserGroup extends Model
20 | {
21 | use HasUuids;
22 | use HasFiles;
23 |
24 | protected $table = 'user_group';
25 |
26 | protected $primaryKey = 'uuid';
27 |
28 | public const CREATED_AT = null;
29 | public const UPDATED_AT = null;
30 |
31 | protected $fillable = [
32 | 'title',
33 | 'description',
34 | 'access',
35 | ];
36 |
37 | protected $guarded = [];
38 |
39 | protected $casts = [
40 | 'title' => 'string',
41 | 'description' => 'string',
42 | 'access' => Json::class,
43 | ];
44 |
45 | protected $attributes = [
46 | 'title' => '',
47 | 'description' => '',
48 | 'access' => '[]',
49 | ];
50 |
51 | protected $hidden = [
52 | 'access',
53 | ];
54 |
55 | public function users(): HasMany
56 | {
57 | return $this->hasMany(User::class, 'group_uuid', 'uuid');
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Domain/Models/UserIntegration.php:
--------------------------------------------------------------------------------
1 | Uuid::class,
42 | 'provider' => 'string',
43 | 'unique' => 'string',
44 | 'date' => 'datetime',
45 | ];
46 |
47 | public function user(): BelongsTo
48 | {
49 | return $this->belongsTo(User::class, 'user_uuid', 'uuid');
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Domain/Models/UserSubscriber.php:
--------------------------------------------------------------------------------
1 | 'string',
33 | 'date' => 'datetime',
34 | ];
35 |
36 | protected $attributes = [
37 | 'email' => '',
38 | 'date' => 'now',
39 | ];
40 | }
41 |
--------------------------------------------------------------------------------
/src/Domain/Models/UserToken.php:
--------------------------------------------------------------------------------
1 | Uuid::class,
44 | 'unique' => 'string',
45 | 'comment' => 'string',
46 | 'ip' => 'string',
47 | 'agent' => 'string',
48 | 'date' => 'datetime',
49 | ];
50 |
51 | protected $attributes = [
52 | 'user_uuid' => '',
53 | 'unique' => '',
54 | 'comment' => '',
55 | 'ip' => '',
56 | 'agent' => '',
57 | 'date' => 'now',
58 | ];
59 |
60 | public function user(): BelongsTo
61 | {
62 | return $this->belongsTo(User::class, 'user_uuid', 'uuid');
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Domain/Plugin/AbstractDeliveryPlugin.php:
--------------------------------------------------------------------------------
1 | routes = true;
18 | $this->handledRoutes = array_merge($this->handledRoutes, $name);
19 | }
20 |
21 | public function getHandledRoute(): array
22 | {
23 | return $this->handledRoutes;
24 | }
25 |
26 | /**
27 | * The function will be executed BEFORE processing the selected route
28 | */
29 | abstract public function before(Request $request, string $routeName): void;
30 |
31 | /**
32 | * The function will be executed AFTER processing the selected route
33 | */
34 | abstract public function after(Request $request, Response $response, string $routeName): Response;
35 | }
36 |
--------------------------------------------------------------------------------
/src/Domain/Plugin/AbstractMailPlugin.php:
--------------------------------------------------------------------------------
1 | logger->info(date('Y-m-d H:i:s') . " - Running LogJob\n");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Domain/Service/Catalog/Exception/AddressAlreadyExistsException.php:
--------------------------------------------------------------------------------
1 | [],
16 | ];
17 | $params = array_merge($default, $params);
18 |
19 | return parent::execute($params);
20 | }
21 |
22 | /**
23 | * @throws \Psr\Container\ContainerExceptionInterface
24 | * @throws \Psr\Container\NotFoundExceptionInterface
25 | * @throws \App\Domain\Service\Task\Exception\TaskNotFoundException
26 | */
27 | protected function action(array $args = []): void
28 | {
29 | if ($this->parameter('image_enable', 'no') === 'no') {
30 | $this->setStatusCancel();
31 |
32 | return;
33 | }
34 |
35 | $fileService = $this->container->get(FileService::class);
36 |
37 | // add task convert
38 | $task = new \App\Domain\Tasks\ConvertImageTask($this->container);
39 | $task->execute([
40 | 'uuid' => $fileService
41 | ->read()
42 | ->filter(fn (\App\Domain\Models\File $file) => str_starts_with($file->type, 'image/'))
43 | ->pluck('uuid'),
44 | ]);
45 |
46 | // run worker
47 | \App\Domain\AbstractTask::worker($task);
48 |
49 | $this->setStatusDone();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Domain/Tasks/SendJSONTask.php:
--------------------------------------------------------------------------------
1 | '',
15 | 'data' => [],
16 | 'files' => [],
17 | ];
18 | $params = array_merge($default, $params);
19 |
20 | return parent::execute($params);
21 | }
22 |
23 | protected function action(array $args = []): void
24 | {
25 | $data = (array) $args['data'];
26 |
27 | if ($args['files']) {
28 | $data['files'] = $args['files'];
29 | }
30 |
31 | $result = file_get_contents($args['url'], false, stream_context_create([
32 | 'http' => [
33 | 'method' => 'POST',
34 | 'content' => json_encode($data),
35 | 'header' => 'Content-Type: application/json;' . PHP_EOL . 'Accept: application/json' . PHP_EOL,
36 | 'timeout' => 30,
37 | ],
38 | ]));
39 |
40 | if ($result !== false) {
41 | $this->container->get(\App\Application\PubSub::class)->publish('task:json:send');
42 |
43 | $this->setStatusDone($result);
44 | } else {
45 | $this->setStatusFail();
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Domain/Traits/HasFiles.php:
--------------------------------------------------------------------------------
1 | $files
11 | * @property Collection $documents
12 | * @property Collection $images
13 | * @property Collection $audios
14 | * @property Collection $videos
15 | */
16 | trait HasFiles
17 | {
18 | public function files(): MorphToMany
19 | {
20 | return $this
21 | ->morphToMany(
22 | File::class,
23 | 'object',
24 | 'file_related',
25 | 'entity_uuid',
26 | 'file_uuid',
27 | )
28 | ->withPivot('comment', 'order')
29 | ->orderBy('file_related.order');
30 | }
31 |
32 | public function documents(): MorphToMany
33 | {
34 | return $this
35 | ->files()
36 | ->where('type', 'like', 'application/%')
37 | ->orWhere('type', 'like', 'text/%');
38 | }
39 |
40 | public function images(): MorphToMany
41 | {
42 | return $this
43 | ->files()
44 | ->where('type', 'like', 'image/%');
45 | }
46 |
47 | public function audios(): MorphToMany
48 | {
49 | return $this
50 | ->files()
51 | ->where('type', 'like', 'audio/%');
52 | }
53 |
54 | public function videos(): MorphToMany
55 | {
56 | return $this
57 | ->files()
58 | ->where('type', 'like', 'video/%');
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Domain/Traits/HasStorage.php:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
{{ 'Access is denied'|locale }}
8 |
9 |
10 |
11 | {% endblock %}
12 |
13 | {% block content %}
14 |
15 |
16 |
17 |
18 |
{{ 'You currently do not have access to the requested page!'|locale }}
19 |
20 | {{ 'If you are sure that the address is typed correctly:'|locale }}
21 | — {{ 'check permissions'|locale }};
22 | — {{ 'contact the administrator'|locale }}.
23 |
24 |
25 |
26 |
27 |
28 | {% endblock %}
29 |
--------------------------------------------------------------------------------
/src/Template/cup/catalog/order/dispatch.twig:
--------------------------------------------------------------------------------
1 | {% extends 'cup/layout.twig' %}
2 |
3 | {% block title %}{{ 'Dispatch Note'|locale }} #{{ order.external_id ?: order.serial }}{% endblock %}
4 |
5 | {% block breadcrumb %}
6 |
7 |
8 |
9 |
{{ 'Dispatch Note'|locale }}
10 |
11 |
19 |
20 |
21 | {% endblock %}
22 |
23 | {% block content %}
24 |
25 | {{ include(template_from_string(template)) }}
26 |
27 | {% endblock %}
28 |
--------------------------------------------------------------------------------
/src/Template/cup/catalog/order/document-view.twig:
--------------------------------------------------------------------------------
1 | {% extends 'cup/layout.twig' %}
2 |
3 | {% block title %}{{ document.title|locale }} #{{ order.external_id ?: order.serial }}{% endblock %}
4 |
5 | {% block breadcrumb %}
6 |
7 |
8 |
9 |
{{ document.title|locale }}
10 |
11 |
19 |
20 |
21 | {% endblock %}
22 |
23 | {% block content %}
24 |
25 | {{ include(template_from_string(template)) }}
26 |
27 | {% endblock %}
28 |
--------------------------------------------------------------------------------
/src/Template/cup/catalog/order/form-modal-product.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {% include 'cup/form.twig' with {
5 | 'label': 'Item'|locale,
6 | 'type': 'text',
7 | 'args': {
8 | 'list': 'products',
9 | 'autocomplete': 'off',
10 | }
11 | } %}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/Template/cup/catalog/product/form-modal-related.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {% include 'cup/form.twig' with {
5 | 'label': 'Item'|locale,
6 | 'type': 'text',
7 | 'args': {
8 | 'list': 'products',
9 | 'autocomplete': 'off',
10 | }
11 | } %}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/Template/cup/catalog/product/index-modal-import.twig:
--------------------------------------------------------------------------------
1 |
2 |
28 |
29 |
--------------------------------------------------------------------------------
/src/Template/cup/donate.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
40 |
--------------------------------------------------------------------------------
/src/Template/cup/form-header.twig:
--------------------------------------------------------------------------------
1 | {#
2 | item - entity
3 | create - header 1
4 | update - header 2
5 | #}
6 |
7 | {% if item is null %}
8 |
{{ create|locale }}
9 | {% else %}
10 |
11 | {{ update|locale }}
12 |
13 |
14 | {% endif %}
15 |
16 |
--------------------------------------------------------------------------------
/src/Template/cup/form-meta.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 | {% include 'cup/form.twig' with {
4 | 'label': 'Meta tag Title'|locale,
5 | 'type': 'text',
6 | 'name': 'meta[title]',
7 | 'args': {
8 | 'value': entity.meta.title,
9 | }
10 | } %}
11 |
12 |
13 | {% include 'cup/form.twig' with {
14 | 'label': 'Meta tag Description'|locale,
15 | 'type': 'text',
16 | 'name': 'meta[description]',
17 | 'args': {
18 | 'value': entity.meta.description,
19 | }
20 | } %}
21 |
22 |
23 | {% include 'cup/form.twig' with {
24 | 'label': 'Meta tag Keywords'|locale,
25 | 'type': 'text',
26 | 'name': 'meta[keywords]',
27 | 'args': {
28 | 'value': entity.meta.keywords,
29 | }
30 | } %}
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/Template/cup/form-save.twig:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/src/Template/cup/form-tags.twig:
--------------------------------------------------------------------------------
1 | {% block tags %}
2 | {% set inputId = random() %}
3 |
4 | {% if args is null %}
5 | {% set args = {} %}
6 | {% endif %}
7 |
8 |
21 |
22 |
27 | {% endblock %}
28 |
--------------------------------------------------------------------------------
/src/Template/cup/reference/deliveries/form-item.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 | {% include 'cup/form.twig' with {
4 | 'label': 'Service'|locale,
5 | 'type': 'select',
6 | 'name': 'value[' ~ (loop.index0 ?? 0) ~ '][uuid]',
7 | 'args': {
8 | 'required': true,
9 | 'option': products,
10 | 'selected': pair.uuid,
11 | }
12 | } %}
13 |
14 |
15 | {% include 'cup/form.twig' with {
16 | 'label': 'Condition'|locale,
17 | 'type': 'number',
18 | 'name': 'value[' ~ (loop.index0 ?? 0) ~ '][condition]',
19 | 'prefix': 'total >='|locale,
20 | 'postfix': '',
21 | 'postfix_btn': '',
22 | 'args': {
23 | 'required': true,
24 | 'value': pair.condition ?? 0,
25 | 'placeholder': 0,
26 | 'step': 'any',
27 | 'min': 0,
28 | }
29 | } %}
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/Template/cup/system/index.twig:
--------------------------------------------------------------------------------
1 | {% extends 'cup/layout.twig' %}
2 |
3 | {% block body %}
4 |
5 |
6 |
12 |
13 | {% include 'cup/system/index-step-' ~ step ~ '.twig' %}
14 |
15 |
21 |
22 |
23 | {% endblock %}
24 |
--------------------------------------------------------------------------------
/src/Template/errors/p400.twig:
--------------------------------------------------------------------------------
1 | {% extends 'layout.twig' %}
2 |
3 | {% block body %}
4 | Bad request
5 | {{ exception.getMessage() }}
6 | {{ exception.getTraceAsString() }}
7 | {% endblock %}
8 |
--------------------------------------------------------------------------------
/src/Template/errors/p403.twig:
--------------------------------------------------------------------------------
1 | {% extends 'layout.twig' %}
2 |
3 | {% block body %}
4 | Forbidden
5 | {% endblock %}
6 |
--------------------------------------------------------------------------------
/src/Template/errors/p404.twig:
--------------------------------------------------------------------------------
1 | {% extends 'layout.twig' %}
2 |
3 | {% block body %}
4 | Not found
5 | {% endblock %}
6 |
--------------------------------------------------------------------------------
/src/Template/errors/p405.twig:
--------------------------------------------------------------------------------
1 | {% extends 'layout.twig' %}
2 |
3 | {% block body %}
4 | Not allowed
5 | {{ methods.implode(' ') }}
6 | {% endblock %}
7 |
--------------------------------------------------------------------------------
/src/Template/errors/p500.twig:
--------------------------------------------------------------------------------
1 | {% extends 'layout.twig' %}
2 |
3 | {% block body %}
4 | {{ exception.getMessage() }}
5 | {{ exception.getTraceAsString() }}
6 | {% endblock %}
7 |
--------------------------------------------------------------------------------
/src/Template/errors/p503.twig:
--------------------------------------------------------------------------------
1 | {% extends 'layout.twig' %}
2 |
3 | {% block body %}
4 | The site is temporarily disabled!
5 | Please try to visit this site later!
6 | {% endblock %}
7 |
--------------------------------------------------------------------------------
/src/Template/layout.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | {% block head '' %}
15 | {% block style '' %}
16 |
17 | {% block title %}{{ title ? title ~ ' | ' : '' }}{{ parameter('common_title', '') }}{% endblock %}
18 |
19 |
20 |
21 | {% block body %}
22 |
23 | {% block bodyinner '' %}
24 | {% block script '' %}
25 |
26 | {% endblock %}
27 |
28 |
--------------------------------------------------------------------------------
/src/Template/mixin/img.twig:
--------------------------------------------------------------------------------
1 | {#
2 | placeholder - image link for placeholder
3 | src - image link
4 | id - attr id
5 | class - attr class
6 | alt - attr alt
7 | title - attr title
8 | style - attr style
9 | args - other args
10 | #}
11 | {% htmlcompress %}
12 |
23 | {% endhtmlcompress %}
24 |
--------------------------------------------------------------------------------
/src/bootstrap.php:
--------------------------------------------------------------------------------
1 | build();
24 |
25 | // include plugins
26 | require PLUGIN_DIR . '/installed.php';
27 |
28 | // instantiate the app
29 | $app = $container->get(\Slim\App::class);
30 |
--------------------------------------------------------------------------------
/src/middleware.php:
--------------------------------------------------------------------------------
1 | add(\App\Application\Middlewares\PluginMiddleware::class);
11 |
12 | // redirect to non-www domain
13 | $app->add(\App\Application\Middlewares\NonWWWMiddleware::class);
14 |
15 | // redirect to address without slash in end
16 | $app->add(function (Request $request, RequestHandlerInterface $handler) {
17 | $path = $request->getUri()->getPath();
18 |
19 | if ($path !== '/' && str_ends_with($path, '/')) {
20 | $query = $request->getUri()->getQuery();
21 |
22 | return (new Response())
23 | ->withAddedHeader('Location', rtrim($path, '/') . ($query ? '?' . $query : ''))
24 | ->withStatus(301);
25 | }
26 |
27 | return $handler->handle($request);
28 | });
29 | };
30 |
--------------------------------------------------------------------------------
/theme/default/main.twig:
--------------------------------------------------------------------------------
1 | {% extends 'layout.twig' %}
2 |
3 | {% set title = 'WebSpace Engine' %}
4 |
5 | {% block head %}
6 |
7 |
8 |
9 |
13 | {% endblock %}
14 |
15 | {% block body %}
16 |
17 | {% block bodyinner %}
18 | {% block page %}
19 | Default page
20 | {% endblock %}
21 | {% endblock %}
22 |
23 | {% endblock %}
24 |
25 |
--------------------------------------------------------------------------------
/theme/default/p400.twig:
--------------------------------------------------------------------------------
1 | Bad request
2 | {{ exception.getMessage() }}
3 | {{ exception.getTraceAsString() }}
4 |
--------------------------------------------------------------------------------
/theme/default/p404.twig:
--------------------------------------------------------------------------------
1 | Not found
2 |
--------------------------------------------------------------------------------
/theme/default/p405.twig:
--------------------------------------------------------------------------------
1 | Not allowed
2 | {{ methods.implode(' ') }}
3 |
4 |
--------------------------------------------------------------------------------
/theme/default/p500.twig:
--------------------------------------------------------------------------------
1 | {{ exception.getMessage() }}
2 | {{ exception.getTraceAsString() }}
3 |
--------------------------------------------------------------------------------
/var/cache/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/var/cache/.gitkeep
--------------------------------------------------------------------------------
/var/log/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/var/log/.gitkeep
--------------------------------------------------------------------------------
/var/upload/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/var/upload/.gitkeep
--------------------------------------------------------------------------------
/var/xml/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getwebspace/platform/f5b666574e03675f18df7b48de619a85f200af51/var/xml/.gitkeep
--------------------------------------------------------------------------------