Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72f684dc97 | ||
|
|
dcd7be9816 | ||
|
|
81d1a070b6 | ||
|
|
0b60c4b908 | ||
|
|
b030000238 |
Generated
-8
@@ -1,8 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
||||||
Generated
-5
@@ -1,5 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<state>
|
|
||||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
|
||||||
</state>
|
|
||||||
</component>
|
|
||||||
Generated
-12
@@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
|
||||||
<data-source source="LOCAL" name="ntspi_db" uuid="3543eabb-ce62-4a3e-9580-690452ad4f73">
|
|
||||||
<driver-ref>mysql.8</driver-ref>
|
|
||||||
<synchronize>true</synchronize>
|
|
||||||
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
|
||||||
<jdbc-url>jdbc:mysql://localhost:3306/ntspi_db</jdbc-url>
|
|
||||||
<working-dir>$ProjectFileDir$</working-dir>
|
|
||||||
</data-source>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
-21
@@ -1,21 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<profile version="1.0">
|
|
||||||
<option name="myName" value="Project Default" />
|
|
||||||
<inspection_tool class="HtmlUnknownTag" enabled="true" level="WARNING" enabled_by_default="true">
|
|
||||||
<option name="myValues">
|
|
||||||
<value>
|
|
||||||
<list size="7">
|
|
||||||
<item index="0" class="java.lang.String" itemvalue="nobr" />
|
|
||||||
<item index="1" class="java.lang.String" itemvalue="noembed" />
|
|
||||||
<item index="2" class="java.lang.String" itemvalue="comment" />
|
|
||||||
<item index="3" class="java.lang.String" itemvalue="noscript" />
|
|
||||||
<item index="4" class="java.lang.String" itemvalue="embed" />
|
|
||||||
<item index="5" class="java.lang.String" itemvalue="script" />
|
|
||||||
<item index="6" class="java.lang.String" itemvalue="div" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
<option name="myCustomValuesEnabled" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
||||||
Generated
-8
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/ntspi-new.iml" filepath="$PROJECT_DIR$/.idea/ntspi-new.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-203
@@ -1,203 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="WEB_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager">
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/app" isTestSource="false" packagePrefix="App\" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/database/factories" isTestSource="false" packagePrefix="Database\Factories\" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/database/seeders" isTestSource="false" packagePrefix="Database\Seeders\" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="Tests\" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/brick/math" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/carbonphp/carbon-doctrine-types" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/dflydev/dot-access-data" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/inflector" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/lexer" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/dragonmantank/cron-expression" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/egulias/email-validator" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/fakerphp/faker" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/filp/whoops" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/fruitcake/php-cors" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/graham-campbell/result-type" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/guzzle" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/promises" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/psr7" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/uri-template" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/hamcrest/hamcrest-php" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/inertiajs/inertia-laravel" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/intervention/image" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/laravel/breeze" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/laravel/framework" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/laravel/pint" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/laravel/prompts" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/laravel/sail" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/laravel/sanctum" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/laravel/serializable-closure" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/laravel/tinker" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/league/commonmark" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/league/config" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/league/flysystem" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/league/flysystem-local" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/league/mime-type-detection" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/mockery/mockery" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/monolog/monolog" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/myclabs/deep-copy" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/nesbot/carbon" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/nette/schema" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/nette/utils" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/nikic/php-parser" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/nunomaduro/collision" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/nunomaduro/termwind" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/manifest" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/version" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpoption/phpoption" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-code-coverage" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-file-iterator" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-invoker" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-text-template" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-timer" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/phpunit" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/clock" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/container" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/event-dispatcher" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-client" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-factory" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-message" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/log" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/simple-cache" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psy/psysh" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/ralouphie/getallheaders" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/ramsey/collection" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/ramsey/uuid" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/cli-parser" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/code-unit" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/comparator" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/complexity" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/diff" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/environment" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/exporter" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/global-state" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/lines-of-code" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-enumerator" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-reflector" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/recursion-context" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/type" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/version" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/console" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/css-selector" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/deprecation-contracts" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/error-handler" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/filesystem" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/finder" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-foundation" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-kernel" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/mailer" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/mime" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-ctype" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-idn" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php80" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php83" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-uuid" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/process" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/routing" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/service-contracts" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/string" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/translation" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/translation-contracts" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/uid" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-dumper" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/yaml" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/theseer/tokenizer" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/tightenco/ziggy" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/tijsverkoyen/css-to-inline-styles" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/vlucas/phpdotenv" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/voku/portable-ascii" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/webmozart/assert" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/anourvalar/eloquent-serialize" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/blade-ui-kit/blade-heroicons" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/blade-ui-kit/blade-icons" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/danharrin/date-format-converter" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/danharrin/livewire-rate-limiting" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/cache" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/dbal" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/deprecations" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/event-manager" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/filament/actions" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/filament/filament" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/filament/forms" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/filament/infolists" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/filament/notifications" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/filament/spatie-laravel-tags-plugin" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/filament/support" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/filament/tables" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/filament/widgets" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/kirschbaum-development/eloquent-power-joins" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/league/csv" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/league/uri" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/league/uri-interfaces" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/livewire/livewire" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/masterminds/html5" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/openspout/openspout" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/cache" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/ryangjchandler/blade-capture-directive" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/color" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/eloquent-sortable" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/invade" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/laravel-package-tools" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/laravel-tags" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/laravel-translatable" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/html-sanitizer" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/awcodes/filament-tiptap-editor" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/mohamedsabil83/filament-forms-tinyeditor" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/scrivo/highlight.php" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/shiki-php" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/ueberdosis/tiptap-php" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/protonemedia/laravel-cross-eloquent-search" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/xvladqt/faker-lorem-flickr" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/ezyang/htmlpurifier" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/maatwebsite/excel" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/maennchen/zipstream-php" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/markbaker/complex" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/markbaker/matrix" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpoffice/phpspreadsheet" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/pxlrbt/filament-excel" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/guava/filament-icon-picker" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/joshembling/image-optimizer" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/bezhansalleh/filament-shield" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/laravel-permission" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/vkcom/vk-php-sdk" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/nicmart/tree" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/browsershot" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/crawler" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/laravel-sitemap" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/robots-txt" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/temporary-directory" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dom-crawler" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/predis/predis" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/yepsua/filament-range-field" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/tomatophp/console-helpers" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/tomatophp/filament-icons" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/imangazaliev/didom" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/opcodesio/log-viewer" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/opcodesio/mail-parser" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/alxdorosenco/porto-for-laravel" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/calebporzio/sushi" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/filament/spatie-laravel-settings-plugin" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/reflection-common" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/type-resolver" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpstan/phpdoc-parser" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/shuvroroy/filament-spatie-laravel-backup" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/db-dumper" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/laravel-backup" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/laravel-settings" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/laravel-signal-aware-command" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
Generated
-224
@@ -1,224 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="LaravelPint">
|
|
||||||
<laravel_pint_settings>
|
|
||||||
<LaravelPintConfiguration tool_path="$PROJECT_DIR$/vendor/bin/pint" />
|
|
||||||
</laravel_pint_settings>
|
|
||||||
</component>
|
|
||||||
<component name="MessDetectorOptionsConfiguration">
|
|
||||||
<option name="transferred" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PHPCSFixerOptionsConfiguration">
|
|
||||||
<option name="transferred" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PHPCodeSnifferOptionsConfiguration">
|
|
||||||
<option name="highlightLevel" value="WARNING" />
|
|
||||||
<option name="transferred" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PhpIncludePathManager">
|
|
||||||
<include_path>
|
|
||||||
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/psr/http-client" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/psr/http-message" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/psr/cache" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/voku/portable-ascii" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/brick/math" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/psy/psysh" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/filp/whoops" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/psr/clock" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/psr/http-factory" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/psr/log" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/psr/simple-cache" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/league/mime-type-detection" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/league/flysystem-local" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/vkcom/vk-php-sdk" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/ezyang/htmlpurifier" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/nette/schema" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/guava/filament-icon-picker" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/nette/utils" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/nesbot/carbon" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/predis/predis" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/league/uri" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/league/commonmark" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/league/uri-interfaces" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/league/csv" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/league/config" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/league/flysystem" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/laravel-sitemap" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/robots-txt" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/laravel-package-tools" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/laravel-translatable" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/ramsey/uuid" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/scrivo/highlight.php" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/pxlrbt/filament-excel" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/ramsey/collection" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/shiki-php" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/laravel-backup" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/eloquent-sortable" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/laravel-tags" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/temporary-directory" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/color" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/browsershot" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/crawler" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/awcodes/filament-tiptap-editor" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/dflydev/dot-access-data" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/vlucas/phpdotenv" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/yepsua/filament-range-field" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/db-dumper" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/laravel-permission" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/laravel-signal-aware-command" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/invade" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/laravel/sail" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/laravel/prompts" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/laravel/serializable-closure" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/laravel/sanctum" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/laravel/tinker" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/laravel/framework" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/egulias/email-validator" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/laravel/pint" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/nicmart/tree" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/monolog/monolog" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/laravel/breeze" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/mockery/mockery" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-ctype" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/translation" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php80" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-idn" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-uuid" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/mailer" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/uid" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/yaml" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php83" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/dom-crawler" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/css-selector" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/html-sanitizer" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/mime" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/string" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/xvladqt/faker-lorem-flickr" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/process" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/doctrine/dbal" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/doctrine/cache" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/filament/infolists" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/filament/filament" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/filament/tables" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/filament/forms" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/fakerphp/faker" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/filament/spatie-laravel-tags-plugin" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/carbonphp/carbon-doctrine-types" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/danharrin/date-format-converter" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/hamcrest/hamcrest-php" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/livewire/livewire" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/filament/notifications" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/filament/widgets" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/filament/support" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/filament/actions" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/opcodesio/mail-parser" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/opcodesio/log-viewer" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/markbaker/complex" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/markbaker/matrix" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/inertiajs/inertia-laravel" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/maennchen/zipstream-php" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/danharrin/livewire-rate-limiting" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/fruitcake/php-cors" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpoption/phpoption" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/ralouphie/getallheaders" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/openspout/openspout" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpoffice/phpspreadsheet" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/tomatophp/filament-icons" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/webmozart/assert" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/tightenco/ziggy" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/tomatophp/console-helpers" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/shuvroroy/filament-spatie-laravel-backup" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/nunomaduro/collision" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/ueberdosis/tiptap-php" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/guzzlehttp/guzzle" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/nunomaduro/termwind" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/guzzlehttp/promises" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/guzzlehttp/psr7" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/anourvalar/eloquent-serialize" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/guzzlehttp/uri-template" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/blade-ui-kit/blade-icons" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/blade-ui-kit/blade-heroicons" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/alxdorosenco/porto-for-laravel" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/bezhansalleh/filament-shield" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/maatwebsite/excel" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/masterminds/html5" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/calebporzio/sushi" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/joshembling/image-optimizer" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/ryangjchandler/blade-capture-directive" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/graham-campbell/result-type" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/dragonmantank/cron-expression" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/mohamedsabil83/filament-forms-tinyeditor" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/protonemedia/laravel-cross-eloquent-search" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/tijsverkoyen/css-to-inline-styles" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/imangazaliev/didom" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/intervention/image" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/kirschbaum-development/eloquent-power-joins" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/spatie/laravel-settings" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpstan/phpdoc-parser" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/filament/spatie-laravel-settings-plugin" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/type-resolver" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-common" />
|
|
||||||
</include_path>
|
|
||||||
</component>
|
|
||||||
<component name="PhpProjectSharedConfiguration" php_language_level="8.1" />
|
|
||||||
<component name="PhpStanOptionsConfiguration">
|
|
||||||
<option name="transferred" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PhpUnit">
|
|
||||||
<phpunit_settings>
|
|
||||||
<PhpUnitSettings configuration_file_path="$PROJECT_DIR$/phpunit.xml" custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" use_configuration_file="true" />
|
|
||||||
</phpunit_settings>
|
|
||||||
</component>
|
|
||||||
<component name="PsalmOptionsConfiguration">
|
|
||||||
<option name="transferred" value="true" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-10
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="PHPSpec">
|
|
||||||
<suites>
|
|
||||||
<PhpSpecSuiteConfiguration>
|
|
||||||
<option name="myPath" value="$PROJECT_DIR$" />
|
|
||||||
</PhpSpecSuiteConfiguration>
|
|
||||||
</suites>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-10
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="PHPUnit">
|
|
||||||
<option name="directories">
|
|
||||||
<list>
|
|
||||||
<option value="$PROJECT_DIR$/tests" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-6
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Vendored
BIN
Binary file not shown.
@@ -9,6 +9,7 @@ use App\Services\Filament\Domain\Posts\PostDataProcessor;
|
|||||||
use App\Services\Filament\Domain\Posts\PostNotificationService;
|
use App\Services\Filament\Domain\Posts\PostNotificationService;
|
||||||
use App\Services\Filament\Domain\Posts\PostSliderService;
|
use App\Services\Filament\Domain\Posts\PostSliderService;
|
||||||
use App\Services\Filament\Domain\Posts\VkPostPublisher;
|
use App\Services\Filament\Domain\Posts\VkPostPublisher;
|
||||||
|
use App\Services\Filament\Domain\Posts\TgPostPublisher;
|
||||||
use App\Services\Filament\Traits\SeoGenerate;
|
use App\Services\Filament\Traits\SeoGenerate;
|
||||||
use Filament\Resources\Pages\CreateRecord;
|
use Filament\Resources\Pages\CreateRecord;
|
||||||
|
|
||||||
@@ -48,6 +49,7 @@ class CreatePost extends CreateRecord
|
|||||||
$this->createSeo($this->record);
|
$this->createSeo($this->record);
|
||||||
$this->sendNotifications();
|
$this->sendNotifications();
|
||||||
$this->publishToVk();
|
$this->publishToVk();
|
||||||
|
$this->publishToTg();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleSlides(): void
|
protected function handleSlides(): void
|
||||||
@@ -74,6 +76,11 @@ class CreatePost extends CreateRecord
|
|||||||
(new VkPostPublisher())->publish($this->publicationAgreements, $this->record);
|
(new VkPostPublisher())->publish($this->publicationAgreements, $this->record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function publishToTg(): void
|
||||||
|
{
|
||||||
|
(new TgPostPublisher())->publish($this->publicationAgreements, $this->record);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,165 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
|
||||||
|
use App\Services\Telegram\TgService;
|
||||||
|
use App\Services\VK\Wall\VkWallService;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use DefStudio\Telegraph\Facades\Telegraph;
|
||||||
|
use DefStudio\Telegraph\Models\TelegraphChat;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class CreateTgPostJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
protected $post_id;
|
||||||
|
protected $title;
|
||||||
|
protected $message;
|
||||||
|
protected $images;
|
||||||
|
protected $videos;
|
||||||
|
protected $documents;
|
||||||
|
protected $publish_date;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
int $post_id, string $title, string $message, array $images = [], array $videos = [], array $documents = [], ?int $publish_date = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->post_id = $post_id;
|
||||||
|
$this->title = $title;
|
||||||
|
$this->message = $message;
|
||||||
|
$this->images = $images;
|
||||||
|
$this->videos = $videos;
|
||||||
|
$this->documents = $documents;
|
||||||
|
$this->publish_date = $publish_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$chat = TelegraphChat::find(1);
|
||||||
|
$baseUrl = config('app.url');
|
||||||
|
$messageIds = [];
|
||||||
|
$captionSent = false;
|
||||||
|
|
||||||
|
// Отправка медиагруппы, если есть изображения или видео
|
||||||
|
if (!empty($this->images) || !empty($this->videos)) {
|
||||||
|
$mediaGroup = $this->createMediaGroup($this->message, $this->images, $this->videos);
|
||||||
|
$response = $chat->mediaGroup($mediaGroup)->send();
|
||||||
|
|
||||||
|
if ($response->successful()) {
|
||||||
|
$messages = $response->json()['result'];
|
||||||
|
$messageIds = array_merge($messageIds, array_map(function($msg) {
|
||||||
|
return $msg['message_id'];
|
||||||
|
}, $messages));
|
||||||
|
Log::info('Media group sent: ' . json_encode($messageIds));
|
||||||
|
$captionSent = true; // Подпись отправлена с медиагруппой
|
||||||
|
} else {
|
||||||
|
Log::error('Failed to send media group: ' . $response->body());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Отправка документов, если они есть
|
||||||
|
if (!empty($this->documents)) {
|
||||||
|
foreach ($this->documents as $index => $document) {
|
||||||
|
$fullDocument = $baseUrl . $document;
|
||||||
|
if ($index == 0 && !$captionSent) {
|
||||||
|
// Отправка первого документа с подписью, если она еще не отправлена
|
||||||
|
$response = $chat->document($fullDocument)->markdown($this->message)->send();
|
||||||
|
$captionSent = true;
|
||||||
|
} else {
|
||||||
|
// Отправка документа без подписи
|
||||||
|
$response = $chat->document($fullDocument)->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response->successful()) {
|
||||||
|
$messageId = $response->telegraphMessageId();
|
||||||
|
$messageIds[] = $messageId;
|
||||||
|
Log::info('Document sent: ' . $messageId);
|
||||||
|
} else {
|
||||||
|
Log::error('Failed to send document: ' . $fullDocument . ' - ' . $response->body());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Отправка текста, если ничего другого не отправлено
|
||||||
|
if (!$captionSent) {
|
||||||
|
$response = $chat->markdown($this->message)->send();
|
||||||
|
|
||||||
|
if ($response->successful()) {
|
||||||
|
$messageId = $response->telegraphMessageId();
|
||||||
|
$messageIds[] = $messageId;
|
||||||
|
Log::info('Text message sent: ' . $messageId);
|
||||||
|
} else {
|
||||||
|
Log::error('Failed to send text message: ' . $response->body());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вставка записи в базу данных
|
||||||
|
if (!empty($messageIds)) {
|
||||||
|
$tgPostId = $messageIds[0];
|
||||||
|
$mediaContent = count($messageIds) > 1 ? json_encode($messageIds) : null;
|
||||||
|
$this->insertPostRecord($tgPostId, $mediaContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function insertPostRecord($tgPostId, $mediaIds)
|
||||||
|
{
|
||||||
|
$mediaContent = is_array($mediaIds) ? json_encode($mediaIds) : $mediaIds;
|
||||||
|
|
||||||
|
DB::table('posts_tg_posts')->insert([
|
||||||
|
'post_id' => $this->post_id,
|
||||||
|
'tg_post_id' => $tgPostId,
|
||||||
|
'media_content' => $mediaContent,
|
||||||
|
'unchange_time_after' => Carbon::now()->addWeek(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createMediaGroup($text, $images, $videos)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$baseUrl = config('app.url');
|
||||||
|
$mediaItems = [];
|
||||||
|
|
||||||
|
// Добавление изображений
|
||||||
|
foreach ($images as $image) {
|
||||||
|
$mediaItems[] = [
|
||||||
|
'type' => 'photo',
|
||||||
|
'media' => $baseUrl . $image,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info('Media items sent: ' . json_encode($mediaItems));
|
||||||
|
|
||||||
|
// Добавление видео
|
||||||
|
foreach ($videos as $video) {
|
||||||
|
$mediaItems[] = [
|
||||||
|
'type' => 'video',
|
||||||
|
'media' => $baseUrl . $video,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ограничение до 10 элементов
|
||||||
|
$mediaItems = array_slice($mediaItems, 0, 10);
|
||||||
|
|
||||||
|
// Установка подписи для первого элемента
|
||||||
|
if (!empty($mediaItems)) {
|
||||||
|
$mediaItems[0]['caption'] = $text;
|
||||||
|
$mediaItems[0]['parse_mode'] = 'Markdown';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $mediaItems;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Ошибка при публикации в Telegram: ' . $e->getMessage());
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Services\VK\Album\VkAlbumService;
|
||||||
|
use App\Services\VK\VkAuthService;
|
||||||
|
use App\Services\VK\VkService;
|
||||||
|
use App\Services\VK\Wall\VkWallService;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use VK\Client\VKApiClient;
|
||||||
|
|
||||||
|
class CreateVkPostJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
protected $post_id;
|
||||||
|
protected $title;
|
||||||
|
protected $message;
|
||||||
|
protected $images;
|
||||||
|
protected $videos;
|
||||||
|
protected $documents;
|
||||||
|
protected $publish_date;
|
||||||
|
protected $public_id;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
int $post_id, string $title, string $message, array $images = [], array $videos = [], array $documents = [], ?int $publish_date = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->post_id = $post_id;
|
||||||
|
$this->title = $title;
|
||||||
|
$this->message = $message;
|
||||||
|
$this->images = $images;
|
||||||
|
$this->videos = $videos;
|
||||||
|
$this->documents = $documents;
|
||||||
|
$this->publish_date = $publish_date;
|
||||||
|
$this->public_id = env('PUBLIC_ID');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$vk = new VKApiClient();
|
||||||
|
$wallService = new VkWallService($vk);
|
||||||
|
|
||||||
|
$from_group = 1;
|
||||||
|
|
||||||
|
$doc_attachments = !empty($this->documents) ? $this->prepareDocuments($this->documents) : '';
|
||||||
|
$doc_list = $doc_attachments ? explode(',', $doc_attachments) : [];
|
||||||
|
$doc_count = count($doc_list);
|
||||||
|
|
||||||
|
if ($doc_count >= 10) {
|
||||||
|
$selected_attachments = array_slice($doc_list, 0, 10);
|
||||||
|
$image_list = [];
|
||||||
|
} else {
|
||||||
|
$video_attachments = !empty($this->videos) ? $this->prepareVideos($this->videos) : '';
|
||||||
|
$video_list = $video_attachments ? explode(',', $video_attachments) : [];
|
||||||
|
$available_slots = 10 - $doc_count;
|
||||||
|
$attached_videos = array_slice($video_list, 0, min(count($video_list), $available_slots));
|
||||||
|
$remaining_slots = $available_slots - count($attached_videos);
|
||||||
|
|
||||||
|
if ($remaining_slots > 0 && !empty($this->images)) {
|
||||||
|
// Подготовка только тех изображений, которые поместятся
|
||||||
|
$images_to_attach = array_slice($this->images, 0, $remaining_slots);
|
||||||
|
$image_attachments = $this->prepareWallPhotos($images_to_attach);
|
||||||
|
$image_list = $image_attachments ? explode(',', $image_attachments) : [];
|
||||||
|
} else {
|
||||||
|
$image_list = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Собираем все вложения с учетом приоритетов
|
||||||
|
$selected_attachments = array_merge($doc_list, $attached_videos, $image_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем, все ли изображения прикреплены
|
||||||
|
if (count($this->images) > count($image_list)) {
|
||||||
|
// Если не все изображения вошли, создаем альбом
|
||||||
|
$album = $this->createAlbum($this->title, $this->images);
|
||||||
|
if (isset($album['id'])) {
|
||||||
|
$albumLink = "https://vk.com/album-{$this->public_id}_{$album['id']}";
|
||||||
|
$this->message .= "\n\n[{$albumLink}|Ссылка на все фотографии]";
|
||||||
|
} else {
|
||||||
|
Log::error('Не удалось создать альбом');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$attachmentString = implode(',', $selected_attachments);
|
||||||
|
|
||||||
|
$vk_post = $wallService->createPost($this->message, $from_group, $attachmentString, $this->publish_date);
|
||||||
|
|
||||||
|
DB::table('posts_vk_posts')->insert(
|
||||||
|
[
|
||||||
|
'post_id' => $this->post_id,
|
||||||
|
'vk_post_id' => $vk_post['post_id'],
|
||||||
|
'unchange_time_after' => Carbon::now()->addWeek(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function prepareWallPhotos(array $images): string
|
||||||
|
{
|
||||||
|
$baseUrl = config('app.url');
|
||||||
|
try {
|
||||||
|
$imagePaths = array_map(function($img) use ($baseUrl) {
|
||||||
|
return $baseUrl . $img;
|
||||||
|
}, $images);
|
||||||
|
|
||||||
|
$photos = $this->uploadWallPhotos($imagePaths, $this->public_id);
|
||||||
|
|
||||||
|
return implode(',', array_map(function($photo) {
|
||||||
|
return "photo{$photo['owner_id']}_{$photo['id']}";
|
||||||
|
}, $photos));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("Ошибка при подготовке фотографий: " . $e->getMessage());
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function prepareVideos(array $videos): string
|
||||||
|
{
|
||||||
|
$baseUrl = config('app.url');
|
||||||
|
$videoPaths = array_map(function($vid) use ($baseUrl) {
|
||||||
|
return $baseUrl . $vid;
|
||||||
|
}, $videos);
|
||||||
|
$uploadedVideos = $this->uploadVideos($videoPaths, $this->public_id);
|
||||||
|
return implode(',', $uploadedVideos);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function prepareDocuments(array $documents): string
|
||||||
|
{
|
||||||
|
$baseUrl = config('app.url');
|
||||||
|
try {
|
||||||
|
$documentPaths = array_map(function($doc) use ($baseUrl) {
|
||||||
|
return $baseUrl . $doc;
|
||||||
|
}, $documents);
|
||||||
|
Log::info(json_encode($documentPaths));
|
||||||
|
$uploadedDocs = $this->uploadDocuments($documentPaths, $this->public_id);
|
||||||
|
return implode(',', $uploadedDocs);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("Ошибка при подготовке документов: " . $e->getMessage());
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function uploadWallPhotos(array $imagePaths, ?int $groupId = null): array
|
||||||
|
{
|
||||||
|
$uploadedPhotos = [];
|
||||||
|
|
||||||
|
foreach ($imagePaths as $imagePath) {
|
||||||
|
try {
|
||||||
|
$uploadServerResponse = Http::get('https://api.vk.com/method/photos.getWallUploadServer', [
|
||||||
|
'group_id' => $groupId,
|
||||||
|
'access_token' => (new VkAuthService())->getToken()->access_token,
|
||||||
|
'v' => '5.131',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$uploadServerData = $uploadServerResponse->json();
|
||||||
|
if (!isset($uploadServerData['response']['upload_url'])) {
|
||||||
|
throw new \Exception('Не удалось получить сервер для загрузки: ' . $imagePath);
|
||||||
|
}
|
||||||
|
$uploadUrl = $uploadServerData['response']['upload_url'];
|
||||||
|
|
||||||
|
$uploadResponse = Http::attach(
|
||||||
|
'photo',
|
||||||
|
file_get_contents($imagePath),
|
||||||
|
basename($imagePath)
|
||||||
|
)->post($uploadUrl);
|
||||||
|
|
||||||
|
$uploadData = $uploadResponse->json();
|
||||||
|
if (!isset($uploadData['photo']) || !isset($uploadData['server']) || !isset($uploadData['hash'])) {
|
||||||
|
throw new \Exception('Не удалось загрузить фотографию: ' . $imagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
$saveResponse = Http::get('https://api.vk.com/method/photos.saveWallPhoto', [
|
||||||
|
'group_id' => $groupId,
|
||||||
|
'photo' => $uploadData['photo'],
|
||||||
|
'server' => $uploadData['server'],
|
||||||
|
'hash' => $uploadData['hash'],
|
||||||
|
'access_token' => (new VkAuthService())->getToken()->access_token,
|
||||||
|
'v' => '5.131',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$saveData = $saveResponse->json();
|
||||||
|
if (!isset($saveData['response'][0])) {
|
||||||
|
throw new \Exception('Не удалось сохранить фотографию: ' . $imagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
$uploadedPhotos[] = $saveData['response'][0];
|
||||||
|
Log::info("Фотография загружена. ID: " . $saveData['response'][0]['id']);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("Ошибка при загрузке {$imagePath}: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $uploadedPhotos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function uploadVideos(array $videoPaths, ?int $groupId = null): array
|
||||||
|
{
|
||||||
|
$uploadedVideos = [];
|
||||||
|
|
||||||
|
foreach ($videoPaths as $videoPath) {
|
||||||
|
try {
|
||||||
|
$saveResponse = Http::timeout(360)->get('https://api.vk.com/method/video.save', [
|
||||||
|
'group_id' => $groupId,
|
||||||
|
'access_token' => (new VkAuthService())->getToken()->access_token,
|
||||||
|
'v' => '5.131',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$saveData = $saveResponse->json();
|
||||||
|
if (!isset($saveData['response']['upload_url'])) {
|
||||||
|
throw new \Exception('Не удалось получить сервер для загрузки видео: ' . $videoPath);
|
||||||
|
}
|
||||||
|
$uploadUrl = $saveData['response']['upload_url'];
|
||||||
|
|
||||||
|
$uploadResponse = Http::timeout(360)->attach(
|
||||||
|
'video_file',
|
||||||
|
file_get_contents($videoPath),
|
||||||
|
basename($videoPath)
|
||||||
|
)->post($uploadUrl);
|
||||||
|
|
||||||
|
$uploadData = $uploadResponse->json();
|
||||||
|
if (!isset($uploadData['video_id']) || !isset($uploadData['owner_id'])) {
|
||||||
|
throw new \Exception('Не удалось загрузить видео: ' . $videoPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
$attachment = "video{$uploadData['owner_id']}_{$uploadData['video_id']}";
|
||||||
|
$uploadedVideos[] = $attachment;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("Ошибка при загрузке видео {$videoPath}: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $uploadedVideos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function uploadDocuments(array $documentPaths, ?int $groupId = null): array
|
||||||
|
{
|
||||||
|
$uploadedDocs = [];
|
||||||
|
|
||||||
|
foreach ($documentPaths as $docPath) {
|
||||||
|
try {
|
||||||
|
// Получение сервера для загрузки документов на стену группы
|
||||||
|
$uploadServerResponse = Http::get('https://api.vk.com/method/docs.getWallUploadServer', [
|
||||||
|
'group_id' => $groupId,
|
||||||
|
'access_token' => (new VkAuthService())->getToken()->access_token,
|
||||||
|
'v' => '5.131',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$uploadServerData = $uploadServerResponse->json();
|
||||||
|
Log::info($uploadServerData);
|
||||||
|
if (!isset($uploadServerData['response']['upload_url'])) {
|
||||||
|
throw new \Exception('Не удалось получить сервер для загрузки документа: ' . $docPath);
|
||||||
|
}
|
||||||
|
$uploadUrl = $uploadServerData['response']['upload_url'];
|
||||||
|
|
||||||
|
// Загрузка документа на сервер
|
||||||
|
$uploadResponse = Http::attach(
|
||||||
|
'file',
|
||||||
|
file_get_contents($docPath),
|
||||||
|
basename($docPath)
|
||||||
|
)->post($uploadUrl);
|
||||||
|
|
||||||
|
$uploadData = $uploadResponse->json();
|
||||||
|
if (!isset($uploadData['file'])) {
|
||||||
|
throw new \Exception('Не удалось загрузить документ: ' . $docPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сохранение документа
|
||||||
|
$saveResponse = Http::get('https://api.vk.com/method/docs.save', [
|
||||||
|
'file' => $uploadData['file'],
|
||||||
|
'access_token' => (new VkAuthService())->getToken()->access_token,
|
||||||
|
'v' => '5.131',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$saveData = $saveResponse->json();
|
||||||
|
|
||||||
|
// Проверка наличия данных о документе
|
||||||
|
if (!isset($saveData['response']['doc'])) {
|
||||||
|
throw new \Exception('Не удалось сохранить документ: ' . $docPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получение данных о документе
|
||||||
|
$doc = $saveData['response']['doc'];
|
||||||
|
$attachment = "doc{$doc['owner_id']}_{$doc['id']}";
|
||||||
|
$uploadedDocs[] = $attachment;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("Ошибка при загрузке документа {$docPath}: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $uploadedDocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createAlbum(string $title, $images)
|
||||||
|
{
|
||||||
|
$vk = new VKApiClient();
|
||||||
|
|
||||||
|
$album = (new VkAlbumService($vk))->createAlbum($title);
|
||||||
|
$uploadServer = (new VkAlbumService($vk))->getServerForUploadImages($album['id'], env('PUBLIC_ID'));
|
||||||
|
foreach (array_chunk($images, 4) as $images_slice) {
|
||||||
|
$images_data = (new VkAlbumService($vk))->uploadImagesToUploadServer($uploadServer['upload_url'], $images_slice);
|
||||||
|
(new VkAlbumService($vk))->saveImagesToUploadServer(
|
||||||
|
$images_data['aid'],
|
||||||
|
$images_data['server'],
|
||||||
|
$images_data['photos_list'],
|
||||||
|
$images_data['hash']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $album;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Enums\LevelEducational;
|
||||||
|
use App\Models\DirectionStudy;
|
||||||
|
use App\Services\Telegram\TgService;
|
||||||
|
use App\Services\Vicon\DirectionStudy\DirectionStudyService;
|
||||||
|
use App\Services\VK\VkService;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Filament\Notifications\Notification;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use VK\Client\VKApiClient;
|
||||||
|
|
||||||
|
class UpdateTgPost implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
readonly private string $text,
|
||||||
|
readonly private array $images = [],
|
||||||
|
readonly private int $post_id,
|
||||||
|
readonly private int|null $publish_date = null,
|
||||||
|
)
|
||||||
|
{}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$postRelation = DB::table('posts_tg_posts')->select()->where('post_id', $this->post_id)->first();
|
||||||
|
$tgService = new TgService();
|
||||||
|
$tgService->updatePost($postRelation->tg_post_id, $this->text, $this->images, json_decode($postRelation->media_content));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Ошибка при создании поста: ' . $e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,338 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Services\VK\Album\VkAlbumService;
|
||||||
|
use App\Services\VK\VkAuthService;
|
||||||
|
use App\Services\VK\VkService;
|
||||||
|
use App\Services\VK\Wall\VkWallService;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use VK\Client\VKApiClient;
|
||||||
|
|
||||||
|
class UpdateVkPostJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
protected $post_id;
|
||||||
|
protected $title;
|
||||||
|
protected $message;
|
||||||
|
protected $images;
|
||||||
|
protected $videos;
|
||||||
|
protected $documents;
|
||||||
|
protected $publish_date;
|
||||||
|
protected $public_id;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
int $post_id, string $title, string $message, array $images = [], array $videos = [], array $documents = [], ?int $publish_date = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->post_id = $post_id;
|
||||||
|
$this->title = $title;
|
||||||
|
$this->message = $message;
|
||||||
|
$this->images = $images;
|
||||||
|
$this->videos = $videos;
|
||||||
|
$this->documents = $documents;
|
||||||
|
$this->publish_date = $publish_date;
|
||||||
|
$this->public_id = env('PUBLIC_ID');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$vk = new VKApiClient();
|
||||||
|
$wallService = new VkWallService($vk);
|
||||||
|
$albumService = new VkAlbumService($vk);
|
||||||
|
|
||||||
|
$postRelation = DB::table('posts_vk_posts')->select()->where('post_id', $this->post_id)->first();
|
||||||
|
$this->post_id = $postRelation->vk_post_id;
|
||||||
|
|
||||||
|
$vk_post = $wallService->getPostById($this->post_id);
|
||||||
|
|
||||||
|
if ($vk_post['attachments']) {
|
||||||
|
$pattern = '/\[https:\/\/vk.com\/album-?[0-9]+_([0-9]+)\|.*\]/';
|
||||||
|
preg_match($pattern, $vk_post['text'], $matches);
|
||||||
|
if (isset($matches[1])) {
|
||||||
|
$album_id = $matches[1];
|
||||||
|
$albumService->deleteAlbum($album_id, $this->public_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$from_group = 1;
|
||||||
|
|
||||||
|
// Подготовка документов
|
||||||
|
$doc_attachments = !empty($this->documents) ? $this->prepareDocuments($this->documents) : '';
|
||||||
|
$doc_list = $doc_attachments ? explode(',', $doc_attachments) : [];
|
||||||
|
$doc_count = count($doc_list);
|
||||||
|
|
||||||
|
if ($doc_count >= 10) {
|
||||||
|
// Если документов 10 или больше, прикрепляем только первые 10
|
||||||
|
$selected_attachments = array_slice($doc_list, 0, 10);
|
||||||
|
$image_list = [];
|
||||||
|
} else {
|
||||||
|
// Подготовка видео
|
||||||
|
$video_attachments = !empty($this->videos) ? $this->prepareVideos($this->videos) : '';
|
||||||
|
$video_list = $video_attachments ? explode(',', $video_attachments) : [];
|
||||||
|
$available_slots = 10 - $doc_count;
|
||||||
|
$attached_videos = array_slice($video_list, 0, min(count($video_list), $available_slots));
|
||||||
|
$remaining_slots = $available_slots - count($attached_videos);
|
||||||
|
|
||||||
|
if ($remaining_slots > 0 && !empty($this->images)) {
|
||||||
|
// Подготовка только тех изображений, которые поместятся
|
||||||
|
$images_to_attach = array_slice($this->images, 0, $remaining_slots);
|
||||||
|
$image_attachments = $this->prepareWallPhotos($images_to_attach);
|
||||||
|
$image_list = $image_attachments ? explode(',', $image_attachments) : [];
|
||||||
|
} else {
|
||||||
|
$image_list = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Собираем все вложения с учетом приоритетов
|
||||||
|
$selected_attachments = array_merge($doc_list, $attached_videos, $image_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем, все ли изображения прикреплены
|
||||||
|
if (count($this->images) > count($image_list)) {
|
||||||
|
// Если не все изображения вошли, создаем альбом
|
||||||
|
$album = $this->createAlbum($this->title, $this->images);
|
||||||
|
if (isset($album['id'])) {
|
||||||
|
$albumLink = "https://vk.com/album-{$this->public_id}_{$album['id']}";
|
||||||
|
$this->message .= "\n\n[{$albumLink}|Ссылка на все фотографии]";
|
||||||
|
} else {
|
||||||
|
Log::error('Не удалось создать альбом');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$attachmentString = implode(',', $selected_attachments);
|
||||||
|
|
||||||
|
$wallService->updatePost($this->post_id, $this->message, $from_group, $attachmentString, $this->publish_date);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAlbumAttachment(array $attachments)
|
||||||
|
{
|
||||||
|
$data = collect($attachments);
|
||||||
|
$filteredAttachment = $data->filter(function($attachment) {
|
||||||
|
return $attachment['type'] === 'album';
|
||||||
|
});
|
||||||
|
return (isset($filteredAttachment[0]) ? $filteredAttachment[0] : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function prepareWallPhotos(array $images): string
|
||||||
|
{
|
||||||
|
$baseUrl = config('app.url');
|
||||||
|
try {
|
||||||
|
$imagePaths = array_map(function($img) use ($baseUrl) {
|
||||||
|
return $baseUrl . $img;
|
||||||
|
}, $images);
|
||||||
|
|
||||||
|
$photos = $this->uploadWallPhotos($imagePaths, $this->public_id);
|
||||||
|
|
||||||
|
return implode(',', array_map(function($photo) {
|
||||||
|
return "photo{$photo['owner_id']}_{$photo['id']}";
|
||||||
|
}, $photos));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("Ошибка при подготовке фотографий: " . $e->getMessage());
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function prepareVideos(array $videos): string
|
||||||
|
{
|
||||||
|
$baseUrl = config('app.url');
|
||||||
|
$videoPaths = array_map(function($vid) use ($baseUrl) {
|
||||||
|
return $baseUrl . $vid;
|
||||||
|
}, $videos);
|
||||||
|
$uploadedVideos = $this->uploadVideos($videoPaths, $this->public_id);
|
||||||
|
return implode(',', $uploadedVideos);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function prepareDocuments(array $documents): string
|
||||||
|
{
|
||||||
|
$baseUrl = config('app.url');
|
||||||
|
try {
|
||||||
|
$documentPaths = array_map(function($doc) use ($baseUrl) {
|
||||||
|
return $baseUrl . $doc;
|
||||||
|
}, $documents);
|
||||||
|
Log::info(json_encode($documentPaths));
|
||||||
|
$uploadedDocs = $this->uploadDocuments($documentPaths, $this->public_id);
|
||||||
|
return implode(',', $uploadedDocs);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("Ошибка при подготовке документов: " . $e->getMessage());
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function uploadWallPhotos(array $imagePaths, ?int $groupId = null): array
|
||||||
|
{
|
||||||
|
$uploadedPhotos = [];
|
||||||
|
|
||||||
|
foreach ($imagePaths as $imagePath) {
|
||||||
|
try {
|
||||||
|
$uploadServerResponse = Http::get('https://api.vk.com/method/photos.getWallUploadServer', [
|
||||||
|
'group_id' => $groupId,
|
||||||
|
'access_token' => (new VkAuthService())->getToken()->access_token,
|
||||||
|
'v' => '5.131',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$uploadServerData = $uploadServerResponse->json();
|
||||||
|
if (!isset($uploadServerData['response']['upload_url'])) {
|
||||||
|
throw new \Exception('Не удалось получить сервер для загрузки: ' . $imagePath);
|
||||||
|
}
|
||||||
|
$uploadUrl = $uploadServerData['response']['upload_url'];
|
||||||
|
|
||||||
|
$uploadResponse = Http::attach(
|
||||||
|
'photo',
|
||||||
|
file_get_contents($imagePath),
|
||||||
|
basename($imagePath)
|
||||||
|
)->post($uploadUrl);
|
||||||
|
|
||||||
|
$uploadData = $uploadResponse->json();
|
||||||
|
if (!isset($uploadData['photo']) || !isset($uploadData['server']) || !isset($uploadData['hash'])) {
|
||||||
|
throw new \Exception('Не удалось загрузить фотографию: ' . $imagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
$saveResponse = Http::get('https://api.vk.com/method/photos.saveWallPhoto', [
|
||||||
|
'group_id' => $groupId,
|
||||||
|
'photo' => $uploadData['photo'],
|
||||||
|
'server' => $uploadData['server'],
|
||||||
|
'hash' => $uploadData['hash'],
|
||||||
|
'access_token' => (new VkAuthService())->getToken()->access_token,
|
||||||
|
'v' => '5.131',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$saveData = $saveResponse->json();
|
||||||
|
if (!isset($saveData['response'][0])) {
|
||||||
|
throw new \Exception('Не удалось сохранить фотографию: ' . $imagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
$uploadedPhotos[] = $saveData['response'][0];
|
||||||
|
Log::info("Фотография загружена. ID: " . $saveData['response'][0]['id']);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("Ошибка при загрузке {$imagePath}: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $uploadedPhotos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function uploadVideos(array $videoPaths, ?int $groupId = null): array
|
||||||
|
{
|
||||||
|
$uploadedVideos = [];
|
||||||
|
|
||||||
|
foreach ($videoPaths as $videoPath) {
|
||||||
|
try {
|
||||||
|
$saveResponse = Http::timeout(360)->get('https://api.vk.com/method/video.save', [
|
||||||
|
'group_id' => $groupId,
|
||||||
|
'access_token' => (new VkAuthService())->getToken()->access_token,
|
||||||
|
'v' => '5.131',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$saveData = $saveResponse->json();
|
||||||
|
if (!isset($saveData['response']['upload_url'])) {
|
||||||
|
throw new \Exception('Не удалось получить сервер для загрузки видео: ' . $videoPath);
|
||||||
|
}
|
||||||
|
$uploadUrl = $saveData['response']['upload_url'];
|
||||||
|
|
||||||
|
$uploadResponse = Http::timeout(360)->attach(
|
||||||
|
'video_file',
|
||||||
|
file_get_contents($videoPath),
|
||||||
|
basename($videoPath)
|
||||||
|
)->post($uploadUrl);
|
||||||
|
|
||||||
|
$uploadData = $uploadResponse->json();
|
||||||
|
if (!isset($uploadData['video_id']) || !isset($uploadData['owner_id'])) {
|
||||||
|
throw new \Exception('Не удалось загрузить видео: ' . $videoPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
$attachment = "video{$uploadData['owner_id']}_{$uploadData['video_id']}";
|
||||||
|
$uploadedVideos[] = $attachment;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("Ошибка при загрузке видео {$videoPath}: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $uploadedVideos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function uploadDocuments(array $documentPaths, ?int $groupId = null): array
|
||||||
|
{
|
||||||
|
$uploadedDocs = [];
|
||||||
|
|
||||||
|
foreach ($documentPaths as $docPath) {
|
||||||
|
try {
|
||||||
|
// Получение сервера для загрузки документов на стену группы
|
||||||
|
$uploadServerResponse = Http::get('https://api.vk.com/method/docs.getWallUploadServer', [
|
||||||
|
'group_id' => $groupId,
|
||||||
|
'access_token' => (new VkAuthService())->getToken()->access_token,
|
||||||
|
'v' => '5.131',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$uploadServerData = $uploadServerResponse->json();
|
||||||
|
Log::info($uploadServerData);
|
||||||
|
if (!isset($uploadServerData['response']['upload_url'])) {
|
||||||
|
throw new \Exception('Не удалось получить сервер для загрузки документа: ' . $docPath);
|
||||||
|
}
|
||||||
|
$uploadUrl = $uploadServerData['response']['upload_url'];
|
||||||
|
|
||||||
|
// Загрузка документа на сервер
|
||||||
|
$uploadResponse = Http::attach(
|
||||||
|
'file',
|
||||||
|
file_get_contents($docPath),
|
||||||
|
basename($docPath)
|
||||||
|
)->post($uploadUrl);
|
||||||
|
|
||||||
|
$uploadData = $uploadResponse->json();
|
||||||
|
if (!isset($uploadData['file'])) {
|
||||||
|
throw new \Exception('Не удалось загрузить документ: ' . $docPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сохранение документа
|
||||||
|
$saveResponse = Http::get('https://api.vk.com/method/docs.save', [
|
||||||
|
'file' => $uploadData['file'],
|
||||||
|
'access_token' => (new VkAuthService())->getToken()->access_token,
|
||||||
|
'v' => '5.131',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$saveData = $saveResponse->json();
|
||||||
|
|
||||||
|
// Проверка наличия данных о документе
|
||||||
|
if (!isset($saveData['response']['doc'])) {
|
||||||
|
throw new \Exception('Не удалось сохранить документ: ' . $docPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получение данных о документе
|
||||||
|
$doc = $saveData['response']['doc'];
|
||||||
|
$attachment = "doc{$doc['owner_id']}_{$doc['id']}";
|
||||||
|
$uploadedDocs[] = $attachment;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("Ошибка при загрузке документа {$docPath}: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $uploadedDocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createAlbum(string $title, $images)
|
||||||
|
{
|
||||||
|
$vk = new VKApiClient();
|
||||||
|
|
||||||
|
$album = (new VkAlbumService($vk))->createAlbum($title);
|
||||||
|
$uploadServer = (new VkAlbumService($vk))->getServerForUploadImages($album['id'], env('PUBLIC_ID'));
|
||||||
|
foreach (array_chunk($images, 4) as $images_slice) {
|
||||||
|
$images_data = (new VkAlbumService($vk))->uploadImagesToUploadServer($uploadServer['upload_url'], $images_slice);
|
||||||
|
(new VkAlbumService($vk))->saveImagesToUploadServer(
|
||||||
|
$images_data['aid'],
|
||||||
|
$images_data['server'],
|
||||||
|
$images_data['photos_list'],
|
||||||
|
$images_data['hash']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $album;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Observers;
|
namespace App\Observers;
|
||||||
|
|
||||||
use App\Containers\Article\Models\Post;
|
use App\Containers\Article\Models\Post;
|
||||||
|
use App\Services\VK\VkService;
|
||||||
use App\Services\App\Cache\PostCacheService;
|
use App\Services\App\Cache\PostCacheService;
|
||||||
|
|
||||||
class PostObserver
|
class PostObserver
|
||||||
@@ -36,6 +37,7 @@ class PostObserver
|
|||||||
public function deleted(Post $post)
|
public function deleted(Post $post)
|
||||||
{
|
{
|
||||||
$this->postCacheService->clearAllCacheByModel();
|
$this->postCacheService->clearAllCacheByModel();
|
||||||
|
app(VkService::class)->deletePost($post->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -0,0 +1,228 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Filament\Domain\Posts;
|
||||||
|
|
||||||
|
use App\Enums\PostStatus;
|
||||||
|
use App\Jobs\CreateTgPost;
|
||||||
|
use App\Jobs\CreateTgPostJob;
|
||||||
|
use App\Jobs\UpdateTgPost;
|
||||||
|
use App\Models\Post;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
class TgPostPublisher
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Публикует пост в социальных сетях.
|
||||||
|
*
|
||||||
|
* @param array $settings
|
||||||
|
* @param Post $post
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function publish(array $settings, Post $post): void
|
||||||
|
{
|
||||||
|
if ($post->status === PostStatus::PUBLISHED) {
|
||||||
|
if ($settings['telegram']) {
|
||||||
|
$imagesFromPost = $post->images;
|
||||||
|
$imagesFromContent = $this->extractImagesFromContent($post->content);
|
||||||
|
$allImages = array_merge($imagesFromPost, $imagesFromContent);
|
||||||
|
$imageLinks = $this->generateImagesForTg($allImages);
|
||||||
|
|
||||||
|
$text = $this->generateContentForTg($post, $allImages);
|
||||||
|
|
||||||
|
$videos = $this->extractVideosFromContent($post->content);
|
||||||
|
$documents = $this->extractFilesFromContent($post->content);
|
||||||
|
|
||||||
|
$publishDate = $post->publish_at > now() ? $post->publish_at->timestamp : null;
|
||||||
|
dispatch(new CreateTgPostJob($post->id, $post->title, $text, $imageLinks, $videos, $documents, $publishDate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(array $settings, Post $post): void
|
||||||
|
{
|
||||||
|
Log::info(json_encode($settings));
|
||||||
|
if ($post->status === PostStatus::PUBLISHED) {
|
||||||
|
if ($settings['telegram']) {
|
||||||
|
$text = $this->generateContentForTg($post->title, $post->content, $post->slug, $post->images);
|
||||||
|
$images = $this->generateImagesForTg($post->images);
|
||||||
|
$publishDate = $post->publish_at > now() ? $post->publish_at->timestamp : null;
|
||||||
|
|
||||||
|
dispatch(new UpdateTgPost($text, $images, $post->id, $publishDate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function generateContentForTg($post, $images): string
|
||||||
|
{
|
||||||
|
$message = '';
|
||||||
|
$message .= "*{$post->title}*\n\n";
|
||||||
|
|
||||||
|
if (is_array($post->content)) {
|
||||||
|
$message .= $this->parseContentBlocks($post->content);
|
||||||
|
} elseif (is_string($post->content)) {
|
||||||
|
$contentBlocks = json_decode($post->content, true);
|
||||||
|
if (is_array($contentBlocks)) {
|
||||||
|
$message .= $this->parseContentBlocks($contentBlocks);
|
||||||
|
} else {
|
||||||
|
$message .= $this->convertToMarkdown($post->content);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message .= $this->convertToMarkdown((string) $post->content);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($post->authors) && is_array($post->authors) && !empty($post->authors)) {
|
||||||
|
$authors = array_map(function($author) {
|
||||||
|
return json_decode('"' . $author . '"');
|
||||||
|
}, $post->authors);
|
||||||
|
$authorLabel = (count($authors) === 1) ? "Автор:" : "Авторы:";
|
||||||
|
$message .= "\n\n$authorLabel " . implode(', ', $authors);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($post->slug) {
|
||||||
|
$url = config('app.url') . "/posts/{$post->slug}";
|
||||||
|
$linkText = "\n\n[Читать полностью]($url)";
|
||||||
|
$linkLength = mb_strlen($linkText);
|
||||||
|
$maxLength = $images ? 1024 : 4096;
|
||||||
|
|
||||||
|
if (mb_strlen($message) > $maxLength - $linkLength) {
|
||||||
|
$truncated = mb_substr($message, 0, $maxLength - $linkLength);
|
||||||
|
$lastSpace = mb_strrpos($truncated, ' ');
|
||||||
|
if ($lastSpace !== false) {
|
||||||
|
$truncated = mb_substr($truncated, 0, $lastSpace);
|
||||||
|
}
|
||||||
|
$message = $truncated . '...';
|
||||||
|
$message .= $linkText;
|
||||||
|
} elseif (count($images) > 10) {
|
||||||
|
$message .= $linkText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return trim($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерирует ссылки на изображения для Телеграмм.
|
||||||
|
*
|
||||||
|
* @param array $images
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function generateImagesForTg(array $images): array
|
||||||
|
{
|
||||||
|
return array_map(function ($file) {
|
||||||
|
return Storage::url($file); // Генерируем полный URL для изображения
|
||||||
|
}, $images);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseContentBlocks(array $blocks): string
|
||||||
|
{
|
||||||
|
$text = '';
|
||||||
|
foreach ($blocks as $block) {
|
||||||
|
switch ($block['type'] ?? '') {
|
||||||
|
case 'heading':
|
||||||
|
if (isset($block['data']['content'])) {
|
||||||
|
$level = $block['data']['level'] ?? 1; // Уровень заголовка, по умолчанию 1
|
||||||
|
$content = $this->convertToMarkdown($block['data']['content']);
|
||||||
|
$text .= str_repeat('#', $level) . ' ' . $content . "\n\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'paragraph':
|
||||||
|
if (isset($block['data']['content'])) {
|
||||||
|
$text .= $this->convertToMarkdown($block['data']['content']) . "\n\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'list':
|
||||||
|
if (isset($block['data']['items']) && is_array($block['data']['items'])) {
|
||||||
|
foreach ($block['data']['items'] as $item) {
|
||||||
|
$text .= "- " . $item . "\n";
|
||||||
|
}
|
||||||
|
$text .= "\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function extractImagesFromContent(array $blocks): array
|
||||||
|
{
|
||||||
|
$images = [];
|
||||||
|
foreach ($blocks as $block) {
|
||||||
|
if ($block['type'] === 'image' && isset($block['data']['url']) && is_array($block['data']['url'])) {
|
||||||
|
foreach ($block['data']['url'] as $imagePath) {
|
||||||
|
$images[] = $imagePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $images;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function extractVideosFromContent(array $blocks): array
|
||||||
|
{
|
||||||
|
$videos = [];
|
||||||
|
foreach ($blocks as $block) {
|
||||||
|
if ($block['type'] === 'video' && isset($block['data']['path'])) {
|
||||||
|
$path = Storage::url($block['data']['path']);
|
||||||
|
$path = stripslashes($path);
|
||||||
|
$videos[] = $path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $videos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function extractFilesFromContent(array $blocks): array
|
||||||
|
{
|
||||||
|
$files = [];
|
||||||
|
foreach ($blocks as $block) {
|
||||||
|
if ($block['type'] === 'files' && isset($block['data']['file']) && is_array($block['data']['file'])) {
|
||||||
|
foreach ($block['data']['file'] as $file) {
|
||||||
|
if (isset($file['path'])) {
|
||||||
|
$files[] = Storage::url($file['path']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function convertToMarkdown(string $text): string
|
||||||
|
{
|
||||||
|
// Декодируем HTML-сущности (например, становится \u00A0)
|
||||||
|
$text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
|
||||||
|
|
||||||
|
// Заменяем неразрывные пробелы на обычные
|
||||||
|
$text = str_replace("\xc2\xa0", " ", $text); // \xc2\xa0 — это \u00A0 в UTF-8
|
||||||
|
|
||||||
|
// Обрабатываем цитаты
|
||||||
|
$text = preg_replace_callback('/<blockquote>(.*?)<\/blockquote>/s', function($match) {
|
||||||
|
$content = $match[1];
|
||||||
|
// Удаляем <p> и заменяем </p> на \n
|
||||||
|
$content = preg_replace('/<p>(.*?)<\/p>/', "$1\n", $content);
|
||||||
|
// Разбиваем на строки и убираем пустые
|
||||||
|
$lines = array_filter(explode("\n", $content), function($line) {
|
||||||
|
return trim($line) !== '';
|
||||||
|
});
|
||||||
|
// Добавляем > перед каждой непустой строкой
|
||||||
|
$quoted = array_map(function($line) {
|
||||||
|
return '> ' . trim($line);
|
||||||
|
}, $lines);
|
||||||
|
return implode("\n", $quoted) . "\n";
|
||||||
|
}, $text);
|
||||||
|
|
||||||
|
// Удаляем <p> и заменяем </p> на \n\n для параграфов
|
||||||
|
$text = preg_replace('/<p>/', '', $text);
|
||||||
|
$text = preg_replace('/<\/p>/', "\n", $text);
|
||||||
|
|
||||||
|
// Обрабатываем жирный текст и курсив, убирая лишние пробелы
|
||||||
|
$text = preg_replace_callback('/<strong>(.*?)<\/strong>/', function($match) {
|
||||||
|
return '*' . trim($match[1]) . '*';
|
||||||
|
}, $text);
|
||||||
|
$text = preg_replace_callback('/<em>(.*?)<\/em>/', function($match) {
|
||||||
|
return '_' . trim($match[1]) . '_';
|
||||||
|
}, $text);
|
||||||
|
// Удаляем оставшиеся HTML-теги
|
||||||
|
$text = strip_tags($text);
|
||||||
|
// Убираем лишние пробелы и пустые строки в начале и конце
|
||||||
|
return trim($text);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,9 @@ use App\Containers\Article\Models\Post;
|
|||||||
use App\Jobs\CreateVkPost;
|
use App\Jobs\CreateVkPost;
|
||||||
use App\Jobs\UpdateVkPost;
|
use App\Jobs\UpdateVkPost;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use App\Jobs\CreateVkPostJob;
|
||||||
|
use App\Jobs\UpdateVkPostJob;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class VkPostPublisher
|
class VkPostPublisher
|
||||||
{
|
{
|
||||||
@@ -19,59 +22,187 @@ class VkPostPublisher
|
|||||||
*/
|
*/
|
||||||
public function publish(array $settings, Post $post): void
|
public function publish(array $settings, Post $post): void
|
||||||
{
|
{
|
||||||
if ($post->status->value === PostStatus::PUBLISHED->value) {
|
if ($post->status === PostStatus::PUBLISHED) {
|
||||||
if ($settings['vk']) {
|
if ($settings['vk']) {
|
||||||
$text = $this->generateContentForVk($post->content);
|
$text = $this->generateContentForVk($post);
|
||||||
$images = $this->generateImageLinksForVk($post->images);
|
|
||||||
|
$imagesFromPost = $post->images;
|
||||||
|
$imagesFromContent = $this->extractImagesFromContent($post->content);
|
||||||
|
$allImages = array_merge($imagesFromPost, $imagesFromContent);
|
||||||
|
$imageLinks = $this->generateImageLinksForVk($allImages);
|
||||||
|
$videos = $this->extractVideosFromContent($post->content);
|
||||||
|
$documents = $this->extractFilesFromContent($post->content);
|
||||||
|
|
||||||
$publishDate = $post->publish_at > now() ? $post->publish_at->timestamp : null;
|
$publishDate = $post->publish_at > now() ? $post->publish_at->timestamp : null;
|
||||||
|
|
||||||
dispatch(new CreateVkPost($post->title, $text, $images, $post->id, $publishDate));
|
dispatch(new CreateVkPostJob(
|
||||||
|
$post->id,
|
||||||
|
$post->title,
|
||||||
|
$text,
|
||||||
|
$imageLinks,
|
||||||
|
$videos,
|
||||||
|
$documents,
|
||||||
|
$publishDate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(array $settings, Post $post): void
|
public function update(array $settings, Post $post): void
|
||||||
{
|
{
|
||||||
if ($post->status->value === PostStatus::PUBLISHED->value) {
|
if ($post->status === PostStatus::PUBLISHED) {
|
||||||
if ($settings['vk']) {
|
if ($settings['vk']) {
|
||||||
|
$text = $this->generateContentForVk($post);
|
||||||
|
|
||||||
|
$imagesFromPost = $post->images;
|
||||||
|
$imagesFromContent = $this->extractImagesFromContent($post->content);
|
||||||
|
$allImages = array_merge($imagesFromPost, $imagesFromContent);
|
||||||
|
$imageLinks = $this->generateImageLinksForVk($allImages);
|
||||||
|
$videos = $this->extractVideosFromContent($post->content);
|
||||||
|
$documents = $this->extractFilesFromContent($post->content);
|
||||||
|
|
||||||
$text = $this->generateContentForVk($post->content);
|
|
||||||
$images = $this->generateImageLinksForVk($post->images);
|
|
||||||
$publishDate = $post->publish_at > now() ? $post->publish_at->timestamp : null;
|
$publishDate = $post->publish_at > now() ? $post->publish_at->timestamp : null;
|
||||||
|
|
||||||
dispatch(new UpdateVkPost($post->title, $text, $images, $post->id, $publishDate));
|
dispatch(new UpdateVkPostJob(
|
||||||
|
$post->id,
|
||||||
|
$post->title,
|
||||||
|
$text,
|
||||||
|
$imageLinks,
|
||||||
|
$videos,
|
||||||
|
$documents,
|
||||||
|
$publishDate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// if ($post->status === PostStatus::PUBLISHED) {
|
||||||
|
// if ($settings['vk']) {
|
||||||
|
// $text = $this->generateContentForVk($post->title, $post->content);
|
||||||
|
// $images = $this->generateImageLinksForVk($post->images);
|
||||||
|
// $publishDate = $post->publish_at > now() ? $post->publish_at->timestamp : null;
|
||||||
|
//
|
||||||
|
// dispatch(new UpdateVkPost($post->title, $text, $images, $post->id, $publishDate));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function generateContentForVk($post): string
|
||||||
* Генерирует текстовый контент для ВКонтакте.
|
{
|
||||||
*
|
$message = '';
|
||||||
* @param array $content
|
$message .= "Название: $post->title\n\n";
|
||||||
* @return string
|
|
||||||
*/
|
if (is_array($post->content)) {
|
||||||
private function generateContentForVk(array $content): string
|
$message .= $this->parseContentBlocks($post->content);
|
||||||
|
} elseif (is_string($post->content)) {
|
||||||
|
$contentBlocks = json_decode($post->content, true);
|
||||||
|
if (is_array($contentBlocks)) {
|
||||||
|
$message .= $this->parseContentBlocks($contentBlocks);
|
||||||
|
} else {
|
||||||
|
$message .= strip_tags($post->content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($post->authors) && is_array($post->authors) && !empty($post->authors)) {
|
||||||
|
$authors = array_map(function($author) {
|
||||||
|
return json_decode('"' . $author . '"');
|
||||||
|
}, $post->authors);
|
||||||
|
$authorLabel = (count($authors) === 1) ? "Автор:" : "Авторы:";
|
||||||
|
$message .= "\n\n$authorLabel " . implode(', ', $authors);
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = html_entity_decode($message);
|
||||||
|
|
||||||
|
// $maxLength = 16000;
|
||||||
|
// $reservedSpace = 200;
|
||||||
|
// $linkText = '';
|
||||||
|
|
||||||
|
// if ($post->slug) {
|
||||||
|
// $url = config('app.url') . "/posts/{$post->slug}";
|
||||||
|
// $linkText = "\n\n[{$url}|Читать полностью]";
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $linkLength = mb_strlen($linkText);
|
||||||
|
//
|
||||||
|
// $maxMLength = $maxLength - $reservedSpace - $linkLength;
|
||||||
|
//
|
||||||
|
// if (mb_strlen($message) > $maxMLength) {
|
||||||
|
// $truncated = mb_substr($message, 0, $maxMLength);
|
||||||
|
// $lastSpace = mb_strrpos($truncated, ' ');
|
||||||
|
// if ($lastSpace !== false) {
|
||||||
|
// $truncated = mb_substr($truncated, 0, $lastSpace);
|
||||||
|
// }
|
||||||
|
// $message = $truncated . '...';
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $message .= $linkText;
|
||||||
|
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseContentBlocks(array $blocks): string
|
||||||
{
|
{
|
||||||
$text = '';
|
$text = '';
|
||||||
foreach ($content as $block) {
|
foreach ($blocks as $block) {
|
||||||
switch ($block['type']) {
|
switch ($block['type'] ?? '') {
|
||||||
case 'paragraph':
|
|
||||||
$text .= strip_tags($block['data']['content']) . "\n\n";
|
|
||||||
break;
|
|
||||||
case 'heading':
|
case 'heading':
|
||||||
$text .= strip_tags($block['data']['content']) . "\n\n";
|
case 'paragraph':
|
||||||
|
if (isset($block['data']['content'])) {
|
||||||
|
$text .= strip_tags($block['data']['content']) . "\n\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'list':
|
||||||
|
if (isset($block['data']['items']) && is_array($block['data']['items'])) {
|
||||||
|
foreach ($block['data']['items'] as $item) {
|
||||||
|
$text .= "- " . $item . "\n";
|
||||||
|
}
|
||||||
|
$text .= "\n";
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return trim($text);
|
return trim($text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function extractImagesFromContent(array $blocks): array
|
||||||
* Генерирует ссылки на изображения для ВКонтакте.
|
{
|
||||||
*
|
$images = [];
|
||||||
* @param array $images
|
foreach ($blocks as $block) {
|
||||||
* @return array
|
if ($block['type'] === 'image' && isset($block['data']['url']) && is_array($block['data']['url'])) {
|
||||||
*/
|
foreach ($block['data']['url'] as $imagePath) {
|
||||||
|
$images[] = $imagePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $images;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function extractVideosFromContent(array $blocks): array
|
||||||
|
{
|
||||||
|
$videos = [];
|
||||||
|
foreach ($blocks as $block) {
|
||||||
|
if ($block['type'] === 'video' && isset($block['data']['path'])) {
|
||||||
|
$path = Storage::url($block['data']['path']);
|
||||||
|
$path = stripslashes($path);
|
||||||
|
$videos[] = $path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $videos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function extractFilesFromContent(array $blocks): array
|
||||||
|
{
|
||||||
|
$files = [];
|
||||||
|
foreach ($blocks as $block) {
|
||||||
|
if ($block['type'] === 'files' && isset($block['data']['file']) && is_array($block['data']['file'])) {
|
||||||
|
foreach ($block['data']['file'] as $file) {
|
||||||
|
if (isset($file['path'])) {
|
||||||
|
$files[] = Storage::url($file['path']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
|
||||||
private function generateImageLinksForVk(array $images): array
|
private function generateImageLinksForVk(array $images): array
|
||||||
{
|
{
|
||||||
return array_map(function ($file) {
|
return array_map(function ($file) {
|
||||||
@@ -79,3 +210,4 @@ class VkPostPublisher
|
|||||||
}, $images);
|
}, $images);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,179 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Telegram;
|
||||||
|
|
||||||
|
use App\Jobs\CreateVkPost;
|
||||||
|
use App\Services\VK\VkService;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use DefStudio\Telegraph\Handlers\WebhookHandler;
|
||||||
|
use DefStudio\Telegraph\Models\TelegraphBot;
|
||||||
|
use DefStudio\Telegraph\Models\TelegraphChat;
|
||||||
|
use App\Models\Post;
|
||||||
|
//use DefStudio\Telegraph\Keyboard\Button;
|
||||||
|
//use DefStudio\Telegraph\Keyboard\Keyboard;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use App\Services\VK\VkAuthService;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
|
||||||
|
class Handler extends WebhookHandler
|
||||||
|
{
|
||||||
|
public function publish(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$post = Post::where('status', 'published')
|
||||||
|
->latest('publish_at')->first();
|
||||||
|
|
||||||
|
// if (!$post) {
|
||||||
|
// $this->reply("Нет опубликованных постов для отправки");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
$chat = TelegraphChat::find(4);
|
||||||
|
log::info($chat);
|
||||||
|
$chat->markdown('zov')->send();
|
||||||
|
|
||||||
|
$message = '';
|
||||||
|
|
||||||
|
$message .= "*{$post->title}*\n\n";
|
||||||
|
|
||||||
|
if (is_array($post->content)) {
|
||||||
|
$message .= $this->parseContentBlocks($post->content);
|
||||||
|
} elseif (is_string($post->content)) {
|
||||||
|
$contentBlocks = json_decode($post->content, true);
|
||||||
|
if (is_array($contentBlocks)) {
|
||||||
|
$message .= $this->parseContentBlocks($contentBlocks);
|
||||||
|
} else {
|
||||||
|
$message .= $this->convertToMarkdown($post->content);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message .= $this->convertToMarkdown((string) $post->content);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($post->slug) {
|
||||||
|
$url = config('app.url') . "posts/{$post->slug}";
|
||||||
|
$message .= "\n\n[Читать полностью]($url)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Отправляем сообщение с Markdown
|
||||||
|
// $this->chat->markdown($message)->send();
|
||||||
|
|
||||||
|
// Обработка изображений и отправка сообщения в Telegram
|
||||||
|
if ($post->images) {
|
||||||
|
$images = is_string($post->images) ? json_decode($post->images, true) : $post->images;
|
||||||
|
$baseUrl = config('app.url'); // Базовый URL, например, https://your-domain.com
|
||||||
|
|
||||||
|
if (is_array($images) && !empty($images)) {
|
||||||
|
$mediaGroup = [];
|
||||||
|
foreach ($images as $index => $image) {
|
||||||
|
$mediaItem = [
|
||||||
|
'type' => 'photo',
|
||||||
|
'media' => config('app.url') . 'storage/' . ltrim($image, '/'),
|
||||||
|
];
|
||||||
|
// Добавляем текст только к первому изображению
|
||||||
|
if ($index === 0) {
|
||||||
|
$mediaItem['caption'] = $message; // Основной текст поста
|
||||||
|
$mediaItem['parse_mode'] = 'Markdown'; // Поддержка Markdown
|
||||||
|
}
|
||||||
|
$mediaGroup[] = $mediaItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// $chat = TelegraphChat::find(0);
|
||||||
|
// $chat->mediaGroup($mediaGroup)->send();
|
||||||
|
|
||||||
|
|
||||||
|
// $page = $chat->page()->content($mediaGroup)->create();
|
||||||
|
// $bot = TelegraphBot::first();
|
||||||
|
// $page = $bot->page()->title($post->title)->content($post->content)->create();
|
||||||
|
// $articleUrl = $page->url();
|
||||||
|
// $url = "https://api.telegram.org/bot7746238162:AAFGi4XwIZ0lnnNL72tlxrmqAgbHmRBMFVs/sendMessage";
|
||||||
|
//
|
||||||
|
// $publishDateTime = strtotime('2025-04-27 20:27:00');
|
||||||
|
// $scheduleDate = Carbon::parse($publishDateTime)->timestamp;
|
||||||
|
//
|
||||||
|
// $data = [
|
||||||
|
// 'chat_id' => $chat,
|
||||||
|
// 'text' => $articleUrl,
|
||||||
|
// 'schedule_date' => $scheduleDate
|
||||||
|
// ];
|
||||||
|
//
|
||||||
|
// $response = Http::post($url, $data);
|
||||||
|
// if ($response->failed()) {
|
||||||
|
// throw new \Exception('Ошибка при планировании поста: ' . $response->body());
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// $publishDate = $post->publish_at > now() ? $post->publish_at->timestamp : null;
|
||||||
|
// dispatch(new CreateVkPost($post->title, $message, $images, $post->id, $publishDate));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$this->chat->markdown($message)->send();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Если нет изображений, отправляем только текст
|
||||||
|
Log::info('dasdsa');
|
||||||
|
$this->chat->markdown($message)->send();
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Ошибка при публикации в Telegram: ' . $e->getMessage());
|
||||||
|
$this->reply("Произошла ошибка при отправке поста");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseContentBlocks(array $blocks): string
|
||||||
|
{
|
||||||
|
$text = '';
|
||||||
|
foreach ($blocks as $block) {
|
||||||
|
$content = $this->decodeUnicode($block['data']['content'] ?? '');
|
||||||
|
switch ($block['type'] ?? '') {
|
||||||
|
case 'heading':
|
||||||
|
$text .= "*" . $content . "*\n\n";
|
||||||
|
break;
|
||||||
|
case 'paragraph':
|
||||||
|
$text .= $this->convertToMarkdown($content) . "\n\n";
|
||||||
|
break;
|
||||||
|
case 'list':
|
||||||
|
if (isset($block['data']['items'])) {
|
||||||
|
foreach ($block['data']['items'] as $item) {
|
||||||
|
$text .= "- " . $item . "\n";
|
||||||
|
}
|
||||||
|
$text .= "\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$text .= $content . "\n\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trim($text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function convertToMarkdown(string $text): string
|
||||||
|
{
|
||||||
|
// Декодируем HTML-сущности
|
||||||
|
$text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
|
||||||
|
$text = $this->decodeUnicode($text);
|
||||||
|
$text = preg_replace('/<p>(.*?)<\/p>/', '$1', $text);
|
||||||
|
$text = preg_replace('/<b>(.*?)<\/b>/', '*$1*', $text);
|
||||||
|
$text = preg_replace('/<i>(.*?)<\/i>/', '_$1_', $text);
|
||||||
|
$text = preg_replace('/<strong>(.*?)<\/strong>/', '*$1*', $text);
|
||||||
|
$text = preg_replace('/<em>(.*?)<\/em>/', '_$1_', $text);
|
||||||
|
// Очищаем от HTML-тегов, декодируем оставшиеся сущности и экранируем спецсимволы для MarkdownV2
|
||||||
|
return strip_tags($text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeUnicode(string $text): string
|
||||||
|
{
|
||||||
|
return preg_replace_callback(
|
||||||
|
'/\\\\u([0-9a-fA-F]{4})/',
|
||||||
|
function ($match) {
|
||||||
|
return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
|
||||||
|
},
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleUnknownCommand(string|\Illuminate\Support\Stringable $command): void
|
||||||
|
{
|
||||||
|
$this->reply("Неизвестная команда: {$command}");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Telegram;
|
||||||
|
|
||||||
|
use DefStudio\Telegraph\Models\TelegraphChat;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class TgService
|
||||||
|
{
|
||||||
|
// public function createPost($text, $images, $videos, $documents, $publishDate)
|
||||||
|
// {
|
||||||
|
// $chat = TelegraphChat::find(4);
|
||||||
|
// Log::info($images);
|
||||||
|
// if ($images !== []){
|
||||||
|
// $images = array_slice($images, 0, 10);
|
||||||
|
// $mediaGroup = $this->createMediaGroup($text, $images);
|
||||||
|
// $response = $chat->mediaGroup($mediaGroup)->send();
|
||||||
|
// if ($response->successful()) {
|
||||||
|
// $messages = $response->json()['result'];
|
||||||
|
// $mediaGroupId = $messages[0]['message_id'];
|
||||||
|
// $messageIds = array_map(function($msg) {
|
||||||
|
// return $msg['message_id'];
|
||||||
|
// }, $messages);
|
||||||
|
// return [$mediaGroupId, $messageIds];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else{
|
||||||
|
// $response = $chat->markdown($text)->send();
|
||||||
|
// if ($response->successful()) {
|
||||||
|
// $messageId = $response->telegraphMessageId();
|
||||||
|
// }
|
||||||
|
// return [$messageId, null];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
public function createPost($text, $images, $videos, $documents, $publishDate)
|
||||||
|
{
|
||||||
|
$chat = TelegraphChat::find(4);
|
||||||
|
Log::info($images);
|
||||||
|
Log::info($videos);
|
||||||
|
Log::info($documents);
|
||||||
|
|
||||||
|
if (!empty($images) || !empty($videos)) {
|
||||||
|
// Создаем медиагруппу из изображений и видео (до 10 элементов)
|
||||||
|
$mediaItems = [];
|
||||||
|
foreach ($images as $image) {
|
||||||
|
$mediaItems[] = ['type' => 'photo', 'media' => $image];
|
||||||
|
}
|
||||||
|
foreach ($videos as $video) {
|
||||||
|
$mediaItems[] = ['type' => 'video', 'media' => $video];
|
||||||
|
}
|
||||||
|
$mediaItems = array_slice($mediaItems, 0, 10);
|
||||||
|
if (!empty($mediaItems)) {
|
||||||
|
$mediaItems[0]['caption'] = $text;
|
||||||
|
$mediaItems[0]['parse_mode'] = 'Markdown';
|
||||||
|
}
|
||||||
|
$response = $chat->mediaGroup($mediaItems)->send();
|
||||||
|
if ($response->successful()) {
|
||||||
|
$messages = $response->json()['result'];
|
||||||
|
$mainMessageId = $messages[0]['message_id'];
|
||||||
|
$mediaMessageIds = array_map(function($msg) {
|
||||||
|
return $msg['message_id'];
|
||||||
|
}, $messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Отправляем документы
|
||||||
|
// $documentMessageIds = [];
|
||||||
|
// foreach ($documents as $document) {
|
||||||
|
// $response = $chat->document($document)->caption($text)->parseMode('Markdown')->send();
|
||||||
|
// if ($response->successful()) {
|
||||||
|
// $documentMessageIds[] = $response->telegraphMessageId();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// $allMessageIds = array_merge($mediaMessageIds, $documentMessageIds);
|
||||||
|
return [$mainMessageId, $mediaMessageIds];
|
||||||
|
} elseif (!empty($documents)) {
|
||||||
|
// Отправляем только документы
|
||||||
|
$documentMessageIds = [];
|
||||||
|
$mainMessageId = null;
|
||||||
|
foreach ($documents as $index => $document) {
|
||||||
|
$response = $chat->document($document)->caption($text)->parseMode('Markdown')->send();
|
||||||
|
if ($response->successful()) {
|
||||||
|
$messageId = $response->telegraphMessageId();
|
||||||
|
$documentMessageIds[] = $messageId;
|
||||||
|
if ($index == 0) {
|
||||||
|
$mainMessageId = $messageId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [$mainMessageId, $documentMessageIds];
|
||||||
|
} else {
|
||||||
|
// Отправляем только текст
|
||||||
|
$response = $chat->markdown($text)->send();
|
||||||
|
if ($response->successful()) {
|
||||||
|
$messageId = $response->telegraphMessageId();
|
||||||
|
return [$messageId, [$messageId]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updatePost($post_id, $text, $images, $media_ids)
|
||||||
|
{
|
||||||
|
$chat = TelegraphChat::find(1);
|
||||||
|
|
||||||
|
if ($images !== []) {
|
||||||
|
try {
|
||||||
|
// if (count($images) !== count($media_ids)) {
|
||||||
|
// foreach ($media_ids as $messageId) {
|
||||||
|
// $chat->deleteMessage($messageId)->send();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $modifiedText = $text . "\n\n_(сообщение изменено)_";
|
||||||
|
//
|
||||||
|
// $result = $this->createPost($modifiedText, $images);
|
||||||
|
//
|
||||||
|
// return [
|
||||||
|
// 'post_id' => $result[0],
|
||||||
|
// 'media_ids' => $result[1] ?? []
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
|
||||||
|
$firstMessageId = $media_ids[0];
|
||||||
|
$chat->editCaption($firstMessageId)
|
||||||
|
->markdown($text)
|
||||||
|
->send();
|
||||||
|
|
||||||
|
// $messageIds = [];
|
||||||
|
// $firstMessageId = null;
|
||||||
|
|
||||||
|
// foreach ($media_ids as $index => $messageId) {
|
||||||
|
// if (!isset($images[$index])) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $newMedia = $images[$index];
|
||||||
|
// $response = $chat->editMedia($messageId)
|
||||||
|
// ->photo(config('app.url') . $newMedia)
|
||||||
|
// ->send();
|
||||||
|
//
|
||||||
|
// if ($response->successful()) {
|
||||||
|
// $updatedMessageId = $response->json()['result']['message_id'];
|
||||||
|
// $messageIds[] = $updatedMessageId;
|
||||||
|
//
|
||||||
|
// if ($index === 0) {
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Ошибка при изменении поста ' . $e->getMessage());
|
||||||
|
return []; // Или null/исключение
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Для текстовых сообщений
|
||||||
|
$chat->edit($post_id)
|
||||||
|
->markdown($text)
|
||||||
|
->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// $chat = TelegraphChat::find(4);
|
||||||
|
// if ($images !== []){
|
||||||
|
// try {
|
||||||
|
// Log::info(json_encode($media_ids));
|
||||||
|
// $firstMessageId = $media_ids[0];
|
||||||
|
// foreach ($media_ids as $index => $messageId) {
|
||||||
|
// $newMedia = $images[$index];
|
||||||
|
// Log::info($newMedia);
|
||||||
|
// Log::info($messageId);
|
||||||
|
// $chat->editMedia($messageId)
|
||||||
|
// ->photo(config('app.url') . $newMedia)
|
||||||
|
// ->send();
|
||||||
|
// }
|
||||||
|
// $chat->editCaption($firstMessageId)
|
||||||
|
// ->markdown($text)
|
||||||
|
// ->send();
|
||||||
|
//
|
||||||
|
// } catch (\Exception $e) {
|
||||||
|
// Log::error('Ошибка при изменении поста ' . $e->getMessage());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else{
|
||||||
|
// $chat->edit($post_id)->markdown($text)->send();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createMediaGroup($text, $images)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$baseUrl = config('app.url');
|
||||||
|
|
||||||
|
if (is_array($images) && !empty($images)) {
|
||||||
|
$mediaGroup = [];
|
||||||
|
foreach ($images as $index => $image) {
|
||||||
|
$mediaItem = [
|
||||||
|
'type' => 'photo',
|
||||||
|
'media' => $baseUrl . $image,
|
||||||
|
// https://crack-gar-specially.ngrok-free.app/storage/posts/gallery/01JT5R37Z05S119VCRRFEADSAG.jpg
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($index === 0) {
|
||||||
|
$mediaItem['caption'] = $text;
|
||||||
|
$mediaItem['parse_mode'] = 'Markdown';
|
||||||
|
}
|
||||||
|
$mediaGroup[] = $mediaItem;
|
||||||
|
}
|
||||||
|
return $mediaGroup;
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Ошибка при публикации в Telegram: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,15 @@ class VkAlbumService
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getServerForUploadImagesOnWall($group_id)
|
||||||
|
{
|
||||||
|
return $this->vk->photos()->getWallUploadServer(
|
||||||
|
$this->vkAuthService->getToken()->access_token,
|
||||||
|
array(
|
||||||
|
'group_id' => $group_id,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function uploadImagesToUploadServer($uploadUrl, $images)
|
public function uploadImagesToUploadServer($uploadUrl, $images)
|
||||||
@@ -83,8 +92,6 @@ class VkAlbumService
|
|||||||
// Обработка ответа
|
// Обработка ответа
|
||||||
$responseData = json_decode($response, true);
|
$responseData = json_decode($response, true);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Удаление временных файлов
|
// Удаление временных файлов
|
||||||
foreach ($localFiles as $localFile) {
|
foreach ($localFiles as $localFile) {
|
||||||
unlink($localFile);
|
unlink($localFile);
|
||||||
@@ -167,5 +174,4 @@ class VkAlbumService
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -33,28 +33,51 @@ class VkAuthService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public function redirectToProvider()
|
||||||
|
// {
|
||||||
|
// $state = bin2hex(random_bytes(16)); // Генерация случайной строки состояния
|
||||||
|
// session(['vk_state' => $state]); //
|
||||||
|
//
|
||||||
|
// $code_verifier = $this->generateCodeVerifier();
|
||||||
|
// $code_challenge = $this->generateCodeChallenge($code_verifier);
|
||||||
|
//
|
||||||
|
// session(['vk_code_verifier' => $code_verifier]);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// $url = 'https://id.vk.com/authorize?' . http_build_query([
|
||||||
|
// 'response_type' => 'code',
|
||||||
|
// 'client_id' => env('VK_APP_ID'),
|
||||||
|
// 'redirect_uri' => env('VK_REDIRECT_URI'),
|
||||||
|
// 'state' => $state,
|
||||||
|
// 'scope' => 'photos wall video docs',
|
||||||
|
// 'code_challenge' => $code_challenge,
|
||||||
|
// 'code_challenge_method' => 's256',
|
||||||
|
// ]);
|
||||||
|
//
|
||||||
|
// return redirect($url);
|
||||||
|
// }
|
||||||
|
|
||||||
public function redirectToProvider()
|
public function redirectToProvider()
|
||||||
{
|
{
|
||||||
$state = bin2hex(random_bytes(16)); // Генерация случайной строки состояния
|
$state = bin2hex(random_bytes(16)); // Генерирует случайную строку состояния (state) для защиты от CSRF-атак.
|
||||||
session(['vk_state' => $state]);
|
session(['vk_state' => $state]); // Сохраняет строку состояния в сессии под ключом 'vk_state'.
|
||||||
|
|
||||||
$code_verifier = $this->generateCodeVerifier();
|
$code_verifier = $this->generateCodeVerifier(); // Создает случайную строку code_verifier для протокола PKCE.
|
||||||
$code_challenge = $this->generateCodeChallenge($code_verifier);
|
$code_challenge = $this->generateCodeChallenge($code_verifier); // Генерирует code_challenge на основе code_verifier (обычно хеш SHA-256).
|
||||||
|
|
||||||
session(['vk_code_verifier' => $code_verifier]);
|
session(['vk_code_verifier' => $code_verifier]); // Сохраняет code_verifier в сессии под ключом 'vk_code_verifier'.
|
||||||
|
|
||||||
|
$url = 'https://id.vk.com/authorize?' . http_build_query([ // Формирует URL для перенаправления на страницу авторизации VK ID с параметрами:
|
||||||
$url = 'https://id.vk.com/authorize?' . http_build_query([
|
'response_type' => 'code', // Указывает, что нужен код авторизации.
|
||||||
'response_type' => 'code',
|
'client_id' => env('VK_APP_ID'), // ID приложения VK из переменных окружения.
|
||||||
'client_id' => env('VK_APP_ID'),
|
'redirect_uri' => env('VK_REDIRECT_URI'), // URI для перенаправления после авторизации.
|
||||||
'redirect_uri' => env('VK_REDIRECT_URI'),
|
'state' => $state, // Передает строку состояния для проверки.
|
||||||
'state' => $state,
|
'scope' => 'photos wall video docs', // Запрашивает доступ к фото, стене, видео и документам.
|
||||||
'scope' => 'photos wall', // Укажите необходимые права доступа
|
'code_challenge' => $code_challenge, // Передает code_challenge для PKCE.
|
||||||
'code_challenge' => $code_challenge, // Добавьте код, если используете PKCE
|
'code_challenge_method' => 's256', // Указывает метод генерации code_challenge (SHA-256).
|
||||||
'code_challenge_method' => 's256',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return redirect($url);
|
return redirect($url); // Перенаправляет пользователя на сформированный URL для авторизации.
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleProviderCallback(Request $request)
|
public function handleProviderCallback(Request $request)
|
||||||
@@ -97,7 +120,7 @@ class VkAuthService
|
|||||||
'client_id' => env('VK_APP_ID'),
|
'client_id' => env('VK_APP_ID'),
|
||||||
'device_id' => $request->device_id,
|
'device_id' => $request->device_id,
|
||||||
'state' => $request->state,
|
'state' => $request->state,
|
||||||
'scope' => 'photos wall',
|
'scope' => 'photos wall video docs',
|
||||||
])->object();
|
])->object();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +132,7 @@ class VkAuthService
|
|||||||
'client_id' => env('VK_APP_ID'),
|
'client_id' => env('VK_APP_ID'),
|
||||||
'device_id' => $device_id,
|
'device_id' => $device_id,
|
||||||
'state' => $state,
|
'state' => $state,
|
||||||
'scope' => 'photos wall',
|
'scope' => 'photos wall video docs',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($response->failed()) {
|
if ($response->failed()) {
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ namespace App\Services\VK;
|
|||||||
|
|
||||||
use App\Services\VK\Album\VkAlbumService;
|
use App\Services\VK\Album\VkAlbumService;
|
||||||
use App\Services\VK\Wall\VkWallService;
|
use App\Services\VK\Wall\VkWallService;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use VK\Client\VKApiClient;
|
use VK\Client\VKApiClient;
|
||||||
|
|
||||||
class VkService
|
class VkService
|
||||||
@@ -16,6 +20,7 @@ class VkService
|
|||||||
$this->wallService = new VkWallService($vk);
|
$this->wallService = new VkWallService($vk);
|
||||||
$this->albumService = new VkAlbumService($vk);
|
$this->albumService = new VkAlbumService($vk);
|
||||||
$this->public_id = env('PUBLIC_ID');
|
$this->public_id = env('PUBLIC_ID');
|
||||||
|
$this->vkAuthService = new VkAuthService();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPosts(int $count = 10)
|
public function getPosts(int $count = 10)
|
||||||
@@ -28,16 +33,50 @@ class VkService
|
|||||||
return $this->wallService->getPostById($id);
|
return $this->wallService->getPostById($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createPost(string $title, string $message, array $images = [], int|null $publish_date = null)
|
// public function createPost(string $title, string $message, array $images = [], array $videos = [], int|null $publish_date = null)
|
||||||
|
// {
|
||||||
|
// $from_group = 1;
|
||||||
|
// $attachments = [];
|
||||||
|
//
|
||||||
|
// if (!empty($images)) {
|
||||||
|
// if (count($images) <= 10) {
|
||||||
|
// $attachments[] = $this->prepareWallPhotos($images);
|
||||||
|
// }
|
||||||
|
// else{
|
||||||
|
// $album = $this->createAlbum($title, $images);
|
||||||
|
// $attachments[] = $this->createAlbumAttachmentParam($album['id']);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $attachmentString = implode(',', $attachments);
|
||||||
|
//
|
||||||
|
// return $this->wallService->createPost($message, $from_group, $attachmentString, $publish_date);
|
||||||
|
// }
|
||||||
|
|
||||||
|
public function createPost(string $title, string $message, array $images = [], array $videos = [], int|null $publish_date = null)
|
||||||
{
|
{
|
||||||
$from_group = 1;
|
$from_group = 1;
|
||||||
$album_attachment = '';
|
$attachments = [];
|
||||||
if ($images !== []) {
|
|
||||||
$album = $this->createAlbum($title, $images);
|
if (!empty($images)) {
|
||||||
$album_attachment = $this->createAlbumAttachmentParam($album['id']);
|
if (count($images) <= 10) {
|
||||||
|
$attachments[] = $this->prepareWallPhotos($images);
|
||||||
|
} else {
|
||||||
|
$attachments[] = $this->prepareWallPhotos(array_slice($images, 0, 10));
|
||||||
|
|
||||||
|
$album = $this->createAlbum($title, $images);
|
||||||
|
if (isset($album['id'])) {
|
||||||
|
$albumLink = "https://vk.com/album-{$this->public_id}_{$album['id']}";
|
||||||
|
$message .= "\n[{$albumLink}|Ссылка на все фотографии]";
|
||||||
|
} else {
|
||||||
|
Log::error('Не удалось создать альбом');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->wallService->createPost($message, $from_group, $album_attachment, $publish_date);
|
$attachmentString = implode(',', $attachments);
|
||||||
|
|
||||||
|
return $this->wallService->createPost($message, $from_group, $attachmentString, $publish_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updatePost(int $id, string $title, string $message, array $images = [], int|null $publish_date = null)
|
public function updatePost(int $id, string $title, string $message, array $images = [], int|null $publish_date = null)
|
||||||
@@ -59,6 +98,22 @@ class VkService
|
|||||||
return $this->wallService->updatePost($id, $message, $from_group, $album_attachment, $publish_date);
|
return $this->wallService->updatePost($id, $message, $from_group, $album_attachment, $publish_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function deletePost(int $post_id){
|
||||||
|
$postRelation = DB::table('posts_vk_posts')->select()->where('post_id', $post_id)->first();
|
||||||
|
$post_id = $postRelation->vk_post_id;
|
||||||
|
$vk_post = $this->getPostById($post_id);
|
||||||
|
|
||||||
|
$pattern = '/\[https:\/\/vk.com\/album-?[0-9]+_([0-9]+)\|.*\]/';
|
||||||
|
preg_match($pattern, $vk_post['text'], $matches);
|
||||||
|
if (isset($matches[1])) {
|
||||||
|
$album_id = $matches[1];
|
||||||
|
$this->albumService->deleteAlbum($album_id, $this->public_id);
|
||||||
|
$this->wallService->deletePost($vk_post['id']);
|
||||||
|
} else {
|
||||||
|
$this->wallService->deletePost($vk_post['id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function createAlbum(string $title, $images)
|
public function createAlbum(string $title, $images)
|
||||||
{
|
{
|
||||||
$album = $this->albumService->createAlbum($title);
|
$album = $this->albumService->createAlbum($title);
|
||||||
@@ -89,4 +144,129 @@ class VkService
|
|||||||
return (isset($filteredAttachment[0]) ? $filteredAttachment[0] : null);
|
return (isset($filteredAttachment[0]) ? $filteredAttachment[0] : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function prepareWallPhotos(array $images){
|
||||||
|
$baseUrl = config('app.url');
|
||||||
|
try {
|
||||||
|
$imagePaths = array_map(function($img) use ($baseUrl) {
|
||||||
|
return $baseUrl . $img;
|
||||||
|
}, $images);
|
||||||
|
|
||||||
|
$photos = $this->uploadWallPhotos($imagePaths, env('PUBLIC_ID'));
|
||||||
|
|
||||||
|
return implode(',', array_map(function($photo) {
|
||||||
|
return "photo{$photo['owner_id']}_{$photo['id']}";
|
||||||
|
}, $photos));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::error("Ошибка: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function prepareVideos(array $videos)
|
||||||
|
{
|
||||||
|
$baseUrl = config('app.url');
|
||||||
|
$videoPaths = array_map(function($vid) use ($baseUrl) {
|
||||||
|
return $baseUrl . $vid;
|
||||||
|
}, $videos);
|
||||||
|
return $this->uploadVideos($videoPaths, env('PUBLIC_ID')); // Возвращает массив, например: ['video123_456', 'video789_012']
|
||||||
|
}
|
||||||
|
|
||||||
|
private function uploadVideos(array $videoPaths, ?int $groupId = null): array
|
||||||
|
{
|
||||||
|
$uploadedVideos = [];
|
||||||
|
|
||||||
|
foreach ($videoPaths as $videoPath) {
|
||||||
|
try {
|
||||||
|
// Шаг 1: Получение сервера для загрузки
|
||||||
|
$saveResponse = Http::get('https://api.vk.com/method/video.save', [
|
||||||
|
'group_id' => $groupId,
|
||||||
|
'access_token' => $this->vkAuthService->getToken()->access_token,
|
||||||
|
'v' => '5.131',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$saveData = $saveResponse->json();
|
||||||
|
if (!isset($saveData['response']['upload_url'])) {
|
||||||
|
throw new Exception('Не удалось получить сервер для загрузки видео: ' . $videoPath);
|
||||||
|
}
|
||||||
|
$uploadUrl = $saveData['response']['upload_url'];
|
||||||
|
|
||||||
|
// Шаг 2: Загрузка видео на сервер
|
||||||
|
$uploadResponse = Http::attach(
|
||||||
|
'video_file',
|
||||||
|
file_get_contents($videoPath),
|
||||||
|
basename($videoPath)
|
||||||
|
)->post($uploadUrl);
|
||||||
|
|
||||||
|
$uploadData = $uploadResponse->json();
|
||||||
|
if (!isset($uploadData['video_id']) || !isset($uploadData['owner_id'])) {
|
||||||
|
throw new Exception('Не удалось загрузить видео: ' . $videoPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$attachment = "video{$uploadData['owner_id']}_{$uploadData['video_id']}";
|
||||||
|
$uploadedVideos[] = $attachment;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::error("Ошибка при загрузке видео {$videoPath}: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $uploadedVideos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function uploadWallPhotos(array $imagePaths, ?int $groupId = null): array
|
||||||
|
{
|
||||||
|
$uploadedPhotos = [];
|
||||||
|
|
||||||
|
foreach ($imagePaths as $imagePath) {
|
||||||
|
try {
|
||||||
|
$uploadServerResponse = Http::get('https://api.vk.com/method/photos.getWallUploadServer', [
|
||||||
|
'group_id' => $groupId,
|
||||||
|
'access_token' => $this->vkAuthService->getToken()->access_token,
|
||||||
|
'v' => '5.131',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$uploadServerData = $uploadServerResponse->json();
|
||||||
|
if (!isset($uploadServerData['response']['upload_url'])) {
|
||||||
|
throw new Exception('Не удалось получить сервер для загрузки для изображения: ' . $imagePath);
|
||||||
|
}
|
||||||
|
$uploadUrl = $uploadServerData['response']['upload_url'];
|
||||||
|
|
||||||
|
// Шаг 2: Загрузка фотографии на сервер
|
||||||
|
$uploadResponse = Http::attach(
|
||||||
|
'photo',
|
||||||
|
file_get_contents($imagePath),
|
||||||
|
basename($imagePath)
|
||||||
|
)->post($uploadUrl);
|
||||||
|
|
||||||
|
$uploadData = $uploadResponse->json();
|
||||||
|
if (!isset($uploadData['photo']) || !isset($uploadData['server']) || !isset($uploadData['hash'])) {
|
||||||
|
throw new Exception('Не удалось загрузить фотографию: ' . $imagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Шаг 3: Сохранение фотографии
|
||||||
|
$saveResponse = Http::get('https://api.vk.com/method/photos.saveWallPhoto', [
|
||||||
|
'group_id' => $groupId,
|
||||||
|
'photo' => $uploadData['photo'],
|
||||||
|
'server' => $uploadData['server'],
|
||||||
|
'hash' => $uploadData['hash'],
|
||||||
|
'access_token' => $this->vkAuthService->getToken()->access_token,
|
||||||
|
'v' => '5.131',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$saveData = $saveResponse->json();
|
||||||
|
if (!isset($saveData['response'][0])) {
|
||||||
|
throw new Exception('Не удалось сохранить фотографию: ' . $imagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавляем данные о загруженной фотографии в массив
|
||||||
|
$uploadedPhotos[] = $saveData['response'][0];
|
||||||
|
Log::info("Фотография успешно загружена. ID: " . $saveData['response'][0]['id']);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Логируем ошибку, но продолжаем загрузку остальных изображений
|
||||||
|
Log::error("Ошибка при загрузке изображения {$imagePath}: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $uploadedPhotos; // Возвращаем массив с данными о загруженных фотографиях
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,7 @@ use VK\Client\VKApiClient;
|
|||||||
class VkWallService
|
class VkWallService
|
||||||
{
|
{
|
||||||
private VKApiClient $vk;
|
private VKApiClient $vk;
|
||||||
|
private VkAuthService $vkAuthService;
|
||||||
private string $wallToken;
|
private string $wallToken;
|
||||||
private string $serviceToken;
|
private string $serviceToken;
|
||||||
private string $publicId;
|
private string $publicId;
|
||||||
@@ -24,7 +25,6 @@ class VkWallService
|
|||||||
$this->publicId = env('PUBLIC_ID');
|
$this->publicId = env('PUBLIC_ID');
|
||||||
$this->publicDomain = env('PUBLIC_DOMAIN');
|
$this->publicDomain = env('PUBLIC_DOMAIN');
|
||||||
$this->vkAuthService = new VkAuthService();
|
$this->vkAuthService = new VkAuthService();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPosts(int $count)
|
public function getPosts(int $count)
|
||||||
@@ -38,22 +38,25 @@ class VkWallService
|
|||||||
|
|
||||||
public function getPostById(int $id)
|
public function getPostById(int $id)
|
||||||
{
|
{
|
||||||
$post = $this->vk->wall()->getById($this->serviceToken, array(
|
try {
|
||||||
'posts' => '-'. $this->publicId . '_' . $id,
|
$post = $this->vk->wall()->getById($this->vkAuthService->getToken()->access_token, array(
|
||||||
));
|
'posts' => '-'. $this->publicId . '_' . $id,
|
||||||
return $post[0];
|
));
|
||||||
|
return $post[0];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Ошибка при попытке получения айди ' . $e->getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function createPost(string $message, int $from_group, string $attachments = '', int|null $publish_date = null)
|
public function createPost(string $message, int $from_group, string $attachments = '', int|null $publish_date = null)
|
||||||
{
|
{
|
||||||
|
$token = $this->vkAuthService->getToken()->access_token;
|
||||||
$params = [
|
$params = [
|
||||||
'owner_id' => '-' . $this->publicId,
|
'owner_id' => '-' . $this->publicId,
|
||||||
'from_group' => $from_group,
|
'from_group' => $from_group,
|
||||||
'message' => $message,
|
'message' => $message,
|
||||||
'attachments' => $attachments,
|
'attachments' => $attachments,
|
||||||
'access_token' => $this->wallToken,
|
'access_token' => $token,
|
||||||
'publish_date' => $publish_date,
|
'publish_date' => $publish_date,
|
||||||
'v' => '5.131',
|
'v' => '5.131',
|
||||||
];
|
];
|
||||||
@@ -88,7 +91,6 @@ class VkWallService
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return $this->vk->wall()->edit(
|
return $this->vk->wall()->edit(
|
||||||
$this->vkAuthService->getToken()->access_token,
|
$this->vkAuthService->getToken()->access_token,
|
||||||
@@ -108,6 +110,36 @@ class VkWallService
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function deletePost(int $post_id)
|
||||||
|
{
|
||||||
|
$token = $this->vkAuthService->getToken()->access_token;
|
||||||
|
$params = [
|
||||||
|
'owner_id' => '-' . $this->publicId,
|
||||||
|
'post_id' => $post_id,
|
||||||
|
'access_token' => $token,
|
||||||
|
'v' => '5.131',
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = Http::asForm()->post('https://api.vk.com/method/wall.delete', $params);
|
||||||
|
|
||||||
|
if ($response->successful() && isset($response['response']) && $response['response'] == 1) {
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
throw new \Exception('Ошибка API: ' . json_encode($response->json()));
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Ошибка при удалении поста: ' . $e->getMessage());
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Не удалось удалить пост: ' . $e->getMessage(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function generateAttachmentsParams(string $attachmentType, int $attachmentId)
|
public function generateAttachmentsParams(string $attachmentType, int $attachmentId)
|
||||||
{
|
{
|
||||||
$pubic_id = env('PUBLIC_ID');
|
$pubic_id = env('PUBLIC_ID');
|
||||||
@@ -117,6 +149,9 @@ class VkWallService
|
|||||||
}
|
}
|
||||||
case 'doc': {
|
case 'doc': {
|
||||||
|
|
||||||
|
}
|
||||||
|
case 'photo': {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"filament/filament": "v3.2.127",
|
"filament/filament": "v3.2.127",
|
||||||
"filament/spatie-laravel-settings-plugin": "^3.2",
|
"filament/spatie-laravel-settings-plugin": "^3.2",
|
||||||
"filament/spatie-laravel-tags-plugin": "v3.2.113",
|
"filament/spatie-laravel-tags-plugin": "v3.2.113",
|
||||||
|
"defstudio/telegraph": "^1.59",
|
||||||
"guava/filament-icon-picker": "2.2.4",
|
"guava/filament-icon-picker": "2.2.4",
|
||||||
"guzzlehttp/guzzle": "^7.8",
|
"guzzlehttp/guzzle": "^7.8",
|
||||||
"imangazaliev/didom": "^2.0",
|
"imangazaliev/didom": "^2.0",
|
||||||
|
|||||||
@@ -0,0 +1,214 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use DefStudio\Telegraph\Telegraph;
|
||||||
|
|
||||||
|
return [
|
||||||
|
/*
|
||||||
|
* Telegram api base url, it can be overridden
|
||||||
|
* for self-hosted servers
|
||||||
|
*/
|
||||||
|
'telegram_api_url' => 'https://api.telegram.org/',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets Telegraph messages default parse mode
|
||||||
|
* allowed values: html|markdown|MarkdownV2
|
||||||
|
*/
|
||||||
|
'default_parse_mode' => Telegraph::PARSE_HTML,
|
||||||
|
|
||||||
|
'webhook' => [
|
||||||
|
/*
|
||||||
|
* Sets the webhook URL that will be exposed by the server,
|
||||||
|
* this can be customized or entirely disabled (by setting it to NULL)
|
||||||
|
*/
|
||||||
|
'url' => '/telegraph/{token}/webhook',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets the handler to be used when Telegraph
|
||||||
|
* receives a new webhook call.
|
||||||
|
*
|
||||||
|
* For reference, see https://docs.defstudio.it/telegraph/webhooks/overview
|
||||||
|
*/
|
||||||
|
'handler' => \App\Services\Telegram\Handler::class,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Middleware to be applied to the webhook route
|
||||||
|
*/
|
||||||
|
'middleware' => [],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets a custom domain when registering a webhook. This will allow a local telegram bot api server
|
||||||
|
* to reach the webhook. Disabled by default
|
||||||
|
*
|
||||||
|
* For reference, see https://core.telegram.org/bots/api#using-a-local-bot-api-server
|
||||||
|
*/
|
||||||
|
// 'domain' => 'http://my.custom.domain',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If enabled, unknown webhook commands are
|
||||||
|
* reported as exception in application logs
|
||||||
|
*/
|
||||||
|
'report_unknown_commands' => env('TELEGRAPH_REPORT_UNKNOWN_COMMANDS', true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* secret token to be sent in a X-Telegram-Bot-Api-Secret-Token header
|
||||||
|
* to verify the authenticity of the webhook
|
||||||
|
*/
|
||||||
|
'secret' => env('TELEGRAPH_WEBHOOK_SECRET'),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* maximum allowed simultaneous connections to the webhook (defaults to 40)
|
||||||
|
*/
|
||||||
|
'max_connections' => env('TELEGRAPH_WEBHOOK_MAX_CONNECTIONS', 40),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of event types for which the webhook should fire.
|
||||||
|
*
|
||||||
|
* Specify a null to receive all update types except `chat_member`, `message_reaction`,
|
||||||
|
* and `message_reaction_count` (by default).
|
||||||
|
*
|
||||||
|
* @see https://core.telegram.org/bots/api#setwebhook
|
||||||
|
*/
|
||||||
|
'allowed_updates' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If enabled, Telegraph dumps received
|
||||||
|
* webhook messages to logs
|
||||||
|
*/
|
||||||
|
'debug' => env('TELEGRAPH_WEBHOOK_DEBUG', false),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets HTTP request timeout when interacting with Telegram servers
|
||||||
|
*/
|
||||||
|
'http_timeout' => env('TELEGRAPH_HTTP_TIMEOUT', 30),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets HTTP connection request timeout when interacting with Telegram servers
|
||||||
|
*/
|
||||||
|
'http_connection_timeout' => env('TELEGRAPH_HTTP_CONNECTION_TIMEOUT', 10),
|
||||||
|
|
||||||
|
'security' => [
|
||||||
|
/*
|
||||||
|
* if enabled, allows callback queries from unregistered chats
|
||||||
|
*/
|
||||||
|
'allow_callback_queries_from_unknown_chats' => true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if enabled, allows messages and commands from unregistered chats
|
||||||
|
*/
|
||||||
|
'allow_messages_from_unknown_chats' => true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if enabled, store unknown chats as new TelegraphChat models
|
||||||
|
*/
|
||||||
|
'store_unknown_chats_in_db' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set model class for both TelegraphBot and TelegraphChat,
|
||||||
|
* to allow more customization.
|
||||||
|
*
|
||||||
|
* Bot model must be or extend `DefStudio\Telegraph\Models\TelegraphBot::class`
|
||||||
|
* Chat model must be or extend `DefStudio\Telegraph\Models\TelegraphChat::class`
|
||||||
|
*/
|
||||||
|
'models' => [
|
||||||
|
'bot' => DefStudio\Telegraph\Models\TelegraphBot::class,
|
||||||
|
'chat' => DefStudio\Telegraph\Models\TelegraphChat::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
'storage' => [
|
||||||
|
/**
|
||||||
|
* Default storage driver to be used for Telegraph data
|
||||||
|
*/
|
||||||
|
'default' => 'file',
|
||||||
|
|
||||||
|
'stores' => [
|
||||||
|
'file' => [
|
||||||
|
/**
|
||||||
|
* Telegraph cache driver to be used, must implement
|
||||||
|
* DefStudio\Telegraph\Contracts\StorageDriver contract
|
||||||
|
*/
|
||||||
|
'driver' => \DefStudio\Telegraph\Storage\FileStorageDriver::class,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Laravel Storage disk to use. See /config/filesystems/disks for available disks
|
||||||
|
* If 'null', Laravel default store will be used,
|
||||||
|
*/
|
||||||
|
'disk' => 'local',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Folder inside filesystem to be used as root for Telegraph storage
|
||||||
|
*/
|
||||||
|
'root' => 'telegraph',
|
||||||
|
],
|
||||||
|
'cache' => [
|
||||||
|
/**
|
||||||
|
* Telegraph cache driver to be used, must implement
|
||||||
|
* DefStudio\Telegraph\Contracts\StorageDriver contract
|
||||||
|
*/
|
||||||
|
'driver' => \DefStudio\Telegraph\Storage\CacheStorageDriver::class,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Laravel Cache store to use. See /config/cache/stores for available stores
|
||||||
|
* If 'null', Laravel default store will be used,
|
||||||
|
*/
|
||||||
|
'store' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prefix to be prepended to cache keys
|
||||||
|
*/
|
||||||
|
'key_prefix' => 'tgph',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attachment validation rules, Telegram bot API defaults are set
|
||||||
|
* can be changed to match higher limits when using a local bot
|
||||||
|
* API server (ref. https://core.telegram.org/bots/api#using-a-local-bot-api-server)
|
||||||
|
*/
|
||||||
|
'attachments' => [
|
||||||
|
'thumbnail' => [
|
||||||
|
'max_size_kb' => 200,
|
||||||
|
'max_height_px' => 320,
|
||||||
|
'max_width_px' => 320,
|
||||||
|
'allowed_ext' => ['jpg'],
|
||||||
|
],
|
||||||
|
'photo' => [
|
||||||
|
'max_size_mb' => 10,
|
||||||
|
'max_ratio' => 20,
|
||||||
|
'height_width_sum_px' => 10000,
|
||||||
|
],
|
||||||
|
'animation' => [
|
||||||
|
'max_size_mb' => 50,
|
||||||
|
],
|
||||||
|
'video' => [
|
||||||
|
'max_size_mb' => 50,
|
||||||
|
],
|
||||||
|
'audio' => [
|
||||||
|
'max_size_mb' => 50,
|
||||||
|
],
|
||||||
|
'document' => [
|
||||||
|
'max_size_mb' => 50,
|
||||||
|
],
|
||||||
|
'sticker' => [
|
||||||
|
'max_size_mb' => 50,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets preferences for commands
|
||||||
|
*/
|
||||||
|
'commands' => [
|
||||||
|
/*
|
||||||
|
* Defines a list of characters that are the identifier of a command sent to the chat.
|
||||||
|
*
|
||||||
|
* Default is `/`
|
||||||
|
*/
|
||||||
|
'start_with' => ['/'],
|
||||||
|
],
|
||||||
|
|
||||||
|
'payments' => [
|
||||||
|
'provider_token' => env('TELEGRAPH_PAYMENT_PROVIDER_TOKEN', ''),
|
||||||
|
],
|
||||||
|
];
|
||||||
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class () extends Migration {
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('telegraph_bots', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('token')->unique();
|
||||||
|
$table->string('name')->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('telegraph_bots');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class () extends Migration {
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('telegraph_chats', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('chat_id');
|
||||||
|
$table->string('name')->nullable();
|
||||||
|
|
||||||
|
$table->foreignId('telegraph_bot_id')->constrained('telegraph_bots')->cascadeOnDelete();
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->unique(['chat_id', 'telegraph_bot_id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('telegraph_chats');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('posts_tg_posts', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedBigInteger('post_id'); // Поле post_id
|
||||||
|
$table->unsignedBigInteger('tg_post_id'); // Поле vk_post_id
|
||||||
|
$table->dateTime('unchange_time_after');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('posts_tg_posts');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('posts_tg_posts', function (Blueprint $table) {
|
||||||
|
$table->text('media_content')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('posts_tg_posts', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('media_content');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user