Last active
November 22, 2023 09:14
-
-
Save antimech/9133c7b97d0e4ca2ce90d8910306a4d2 to your computer and use it in GitHub Desktop.
Здесь фрагменты кода в одном из старых проектов под NDA (к которому есть доступ из дома) опубликованные с разрешения их владельцев, здесь только начинаю применять сервис-классы. Проект сделан на Laravel + Botman.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use App\Http\Controllers\BotManController; | |
use Illuminate\Support\Facades\Log; | |
$botman = resolve('botman'); | |
$botman->hears('/start', BotManController::class . '@welcome'); | |
$botman->hears('Add', BotManController::class . '@createAlert'); | |
$botman->hears('Show', BotManController::class . '@showAlerts'); | |
$botman->hears('Remove', BotManController::class . '@removeAlert'); | |
// Cancel any conversation | |
$botman->hears('/stop', function ($bot) { | |
$bot->reply('Stopped.'); | |
})->stopsConversation(); | |
// Handle incorrect commands | |
$botman->fallback(function ($bot) { | |
$bot->reply('Sorry, I did not understand these commands.'); | |
}); | |
// Handle exceptions | |
$botman->exception(Exception::class, function ($exception, $bot) { | |
Log::error($exception); | |
$bot->reply('Sorry, something went wrong. Try again later, please.'); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Http\Controllers; | |
use App\Conversations\AddAlertConversation; | |
use App\Conversations\RemoveAlertConversation; | |
use App\Services\TimeGapService; | |
use App\TelegramUser; | |
use BotMan\BotMan\BotMan; | |
use Illuminate\Database\Eloquent\ModelNotFoundException; | |
class BotManController extends Controller | |
{ | |
public function __construct( | |
protected TimeGapService $timeGapService | |
) {} | |
/** | |
* Place your BotMan logic here. | |
*/ | |
public function handle(): void | |
{ | |
$botman = app('botman'); | |
$botman->listen(); | |
} | |
/** | |
* Loaded through routes/botman.php | |
*/ | |
public function welcome(BotMan $bot): void | |
{ | |
$botUser = $bot->getUser(); | |
$telegramUser = TelegramUser::updateOrCreate(['id' => $botUser->getId()], [ | |
'first_name' => $botUser->getFirstName(), | |
'last_name' => $botUser->getLastName(), | |
'username' => $botUser->getUsername(), | |
]); | |
// Fix for failing BotMan test | |
if (app()->runningUnitTests() === false) { | |
$telegramUser->update([ | |
'language_code' => $botUser->getLanguageCode(), | |
]); | |
} | |
$menuKeyboard = [ | |
['Add', 'Show'], | |
['Remove'], | |
]; | |
$bot->reply('Welcome! What do you want to do with your alerts?', [ | |
'reply_markup' => json_encode([ | |
'keyboard' => $menuKeyboard, | |
'one_time_keyboard' => false, | |
'resize_keyboard' => true | |
]) | |
]); | |
} | |
/** | |
* Create an alert. | |
*/ | |
public function createAlert(BotMan $bot): void | |
{ | |
$bot->startConversation(new AddAlertConversation); | |
} | |
/** | |
* Show user's alerts. | |
*/ | |
public function showAlerts(BotMan $bot): mixed | |
{ | |
$telegramUserId = $bot->getUser()->getId(); | |
try { | |
$telegramUser = TelegramUser::findOrFail($telegramUserId); | |
} catch (ModelNotFoundException) { | |
return $bot->reply('Restart the bot, please: /start'); | |
} | |
$alerts = $telegramUser->alerts; | |
if ($alerts->isEmpty()) { | |
return $bot->reply('You don\'t have any alerts yet.'); | |
} | |
$message = "*Ticker | Percent | Timeframe*\n"; | |
foreach ($alerts as $alert) { | |
$humanReadableTimeframe = $this->timeGapService->secondsToTimeframe($alert->timeframe); | |
$message .= "{$alert->coinPair->ticker} | {$alert->value_change_percent}% | $humanReadableTimeframe\n"; | |
} | |
return $bot->reply($message, [ | |
'parse_mode' => 'Markdown' | |
]); | |
} | |
/** | |
* Delete specific alert. | |
*/ | |
public function removeAlert(BotMan $bot): void | |
{ | |
$bot->startConversation(new RemoveAlertConversation); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Models; | |
use Illuminate\Database\Eloquent\Model; | |
use Illuminate\Database\Eloquent\Relations\BelongsTo; | |
class Alert extends Model | |
{ | |
/** | |
* The attributes that are mass assignable. | |
* | |
* @var array<int, string> | |
*/ | |
protected $fillable = [ | |
'value_change_percent', 'timeframe', 'recent_alerts_count', 'triggered_at', | |
]; | |
/** | |
* The attributes that should be cast. | |
* | |
* @var array<string, string> | |
*/ | |
protected $casts = [ | |
'triggered_at' => 'datetime', | |
]; | |
/** | |
* Get the coin pair to which this alert applies. | |
*/ | |
public function coinPair(): BelongsTo | |
{ | |
return $this->belongsTo(CoinPair::class); | |
} | |
/** | |
* Get the user who subscribed to this alert. | |
*/ | |
public function subscriber(): BelongsTo | |
{ | |
return $this->belongsTo(TelegramUser::class, 'telegram_user_id'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Models; | |
use Illuminate\Database\Eloquent\Model; | |
use Illuminate\Database\Eloquent\Relations\HasMany; | |
class Coin extends Model | |
{ | |
/** | |
* The attributes that are mass assignable. | |
* | |
* @var array<int, string> | |
*/ | |
protected $fillable = [ | |
'code', | |
]; | |
public function basePairs(): HasMany | |
{ | |
return $this->hasMany(CoinPair::class, 'base_id'); | |
} | |
public function quotedPairs(): HasMany | |
{ | |
return $this->hasMany(CoinPair::class, 'quoted_id'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Models; | |
use Illuminate\Database\Eloquent\Model; | |
use Illuminate\Database\Eloquent\Relations\BelongsTo; | |
use Illuminate\Database\Eloquent\Relations\HasMany; | |
class CoinPair extends Model | |
{ | |
/** | |
* Get the base coin. | |
*/ | |
public function baseCoin(): BelongsTo | |
{ | |
return $this->belongsTo(Coin::class, 'base_id'); | |
} | |
/** | |
* Get the quoted coin. | |
*/ | |
public function quotedCoin(): BelongsTo | |
{ | |
return $this->belongsTo(Coin::class, 'quoted_id'); | |
} | |
/** | |
* Get value history of the coin pair. | |
*/ | |
public function values(): HasMany | |
{ | |
return $this->hasMany(CoinPairValue::class); | |
} | |
/** | |
* Get previous value of the coin pair. | |
*/ | |
public function getPreviousValueAttribute(): float { | |
if ($this->values()->count() < 2) { | |
return false; | |
} | |
return $this->values()->latest()->skip(1)->take(1)->first()->value; | |
} | |
/** | |
* Get current value of the coin pair. | |
*/ | |
public function getValueAttribute(): float | |
{ | |
if ($this->values()->count() === 0) { | |
return false; | |
} | |
return $this->values()->latest()->first()->value; | |
} | |
/** | |
* Get the coin pair's ticker. | |
*/ | |
public function getTickerAttribute(): string | |
{ | |
return "{$this->baseCoin->code}/{$this->quotedCoin->code}"; | |
} | |
/** | |
* Get alerts related to this coin pair. | |
*/ | |
public function alerts(): HasMany | |
{ | |
return $this->hasMany(Alert::class); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Models; | |
use Illuminate\Database\Eloquent\Model; | |
use Illuminate\Database\Eloquent\Relations\BelongsTo; | |
class CoinPairValue extends Model | |
{ | |
/** | |
* The attributes that are mass assignable. | |
* | |
* @var array<int, string> | |
*/ | |
protected $fillable = [ | |
'value', | |
]; | |
/** | |
* Get the coin pair to which this value applies. | |
*/ | |
public function coinPair(): BelongsTo | |
{ | |
return $this->belongsTo(CoinPair::class); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Models; | |
use Illuminate\Database\Eloquent\Model; | |
use Illuminate\Database\Eloquent\Relations\HasMany; | |
class TelegramUser extends Model | |
{ | |
/** | |
* The attributes that are mass assignable. | |
* | |
* @var array<int, string> | |
*/ | |
protected $fillable = [ | |
'id', 'first_name', 'last_name', 'username', 'language_code', | |
]; | |
/** | |
* Get user's alerts. | |
*/ | |
public function alerts(): HasMany | |
{ | |
return $this->hasMany(Alert::class); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Services; | |
use Carbon\Carbon; | |
class TimeGapService | |
{ | |
/** | |
* Translate human-readable timeframe (from "1m" up to "24h") into seconds. | |
*/ | |
public function recognizeTimeframeString(string $timeframe): bool|int | |
{ | |
// Validate timeframe string | |
if (!preg_match('/^([1-9]|1[0-9]|2[0-4])(h)|([1-9]|[1-5][0-9])(m)$/', $timeframe)) { | |
return false; | |
} | |
// Recognize timeframe | |
$timeframeShortcuts = ['m', 'h']; | |
$timeframeWords = ['minutes', 'hours']; | |
$timeframeToParse = str_replace($timeframeShortcuts, $timeframeWords, $timeframe); | |
$parsedTimeframe = Carbon::parse($timeframeToParse)->diffInSeconds() + 1; | |
if ($timeframeToParse === '24hours') { | |
$parsedTimeframe = 86400; | |
} | |
return $parsedTimeframe; | |
} | |
/** | |
* Translate seconds into human-readable timeframe. | |
*/ | |
public function secondsToTimeframe(int $seconds): string | |
{ | |
$timeframeMinutes = $seconds / 60; | |
$timeframeHours = $timeframeMinutes / 60; | |
if ($timeframeHours >= 1) { | |
$humanReadableTimeframe = "{$timeframeHours}h"; | |
} else { | |
$humanReadableTimeframe = "{$timeframeMinutes}m"; | |
} | |
return $humanReadableTimeframe; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment