Recherche des tweets de réponse avec l'API Tweeter
This commit is contained in:
56
app/Console/Commands/ImportUsersCommand.php
Normal file
56
app/Console/Commands/ImportUsersCommand.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\Account;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class ImportUsersCommand extends Command
|
||||
{
|
||||
protected $signature = 'import:users {file}';
|
||||
protected $description = 'Import users from a text file';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$filePath = $this->argument('file');
|
||||
|
||||
if (!file_exists($filePath)) {
|
||||
$this->error("Le fichier spécifié n'existe pas.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
$file = fopen($filePath, 'r');
|
||||
|
||||
while (($line = fgets($file)) !== false) {
|
||||
$data = explode(':', trim($line));
|
||||
|
||||
if (count($data) < 5) {
|
||||
$this->error("Format incorrect dans le fichier.");
|
||||
continue;
|
||||
}
|
||||
|
||||
[$username, $password, $email, $emailPassword, $token] = $data;
|
||||
|
||||
Account::create([
|
||||
'name' => $username,
|
||||
'password' => $password,
|
||||
'rambler_email' => $email,
|
||||
'rambler_password' => $emailPassword,
|
||||
'auth_token' => $token,
|
||||
]);
|
||||
|
||||
$this->info("Utilisateur {$username} importé avec succès.");
|
||||
}
|
||||
|
||||
fclose($file);
|
||||
|
||||
$this->info("Importation terminée.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
557
app/Http/Controllers/APIController.php
Normal file
557
app/Http/Controllers/APIController.php
Normal file
@@ -0,0 +1,557 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Subscriber\Oauth\Oauth1;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class APIController extends Controller
|
||||
{
|
||||
protected $twitterHeaders = [
|
||||
'User-Agent' => 'TwitterAndroid/10.46.0-release.0 (310460000-r-0) Android+SDK+built+for+x86/11 (unknown;Android+SDK+built+for+x86;Android;sdk_phone_x86;0;;1;2013)',
|
||||
'x-twitter-client-language' => 'en-US',
|
||||
'x-twitter-client-version' => '10.46.0-release.0',
|
||||
'x-twitter-client' => 'TwitterAndroid',
|
||||
'x-twitter-api-version' => '5',
|
||||
'x-twitter-active-user' => 'yes',
|
||||
'os-version' => '30',
|
||||
'x-attest-token' => 'no_token',
|
||||
];
|
||||
|
||||
public function retweet($user, $tweetid)
|
||||
{
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/graphql/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
$params = [
|
||||
"features" => json_encode([
|
||||
"longform_notetweets_inline_media_enabled" => true,
|
||||
"super_follow_badge_privacy_enabled" => true,
|
||||
"longform_notetweets_rich_text_read_enabled" => true,
|
||||
"super_follow_user_api_enabled" => true,
|
||||
"super_follow_tweet_api_enabled" => true,
|
||||
"articles_api_enabled" => true,
|
||||
"android_graphql_skip_api_media_color_palette" => true,
|
||||
"creator_subscriptions_tweet_preview_api_enabled" => true,
|
||||
"freedom_of_speech_not_reach_fetch_enabled" => true,
|
||||
"tweetypie_unmention_optimization_enabled" => true,
|
||||
"longform_notetweets_consumption_enabled" => true,
|
||||
"subscriptions_verification_info_enabled" => true,
|
||||
"blue_business_profile_image_shape_enabled" => true,
|
||||
"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled" => true,
|
||||
"immersive_video_status_linkable_timestamps" => true,
|
||||
"super_follow_exclusive_tweet_notifications_enabled" => true,
|
||||
]),
|
||||
"variables" => json_encode([
|
||||
"includeTweetImpression" => true,
|
||||
"includeHasBirdwatchNotes" => false,
|
||||
"includeEditPerspective" => false,
|
||||
"tweet_id" => $tweetid,
|
||||
"includeEditControl" => true,
|
||||
"includeTweetVisibilityNudge" => true,
|
||||
])
|
||||
];
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->post('24zITFB5aD73PxYtmc6pkA/CreateRetweet', [
|
||||
'headers' => $this->twitterHeaders, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth',
|
||||
'json' => $params
|
||||
]);
|
||||
|
||||
if ($res->getStatusCode() != 200) {
|
||||
$text = "Le compte twitter ".$user->Name." a été désactivé";
|
||||
|
||||
Http::get('https://api.telegram.org/bot7036172799:AAEVZXHu4SL64VWN5c0AxM1BVxvB0-k6lT0/sendMessage?chat_id=1970698501&text=' . urlencode($text));
|
||||
|
||||
$user->enabled = false;
|
||||
$user->save();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function reply($user, $tweetid, $text)
|
||||
{
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/graphql/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
$params = [
|
||||
"features" => json_encode([
|
||||
"longform_notetweets_inline_media_enabled" => true,
|
||||
"super_follow_badge_privacy_enabled" => true,
|
||||
"longform_notetweets_rich_text_read_enabled" => true,
|
||||
"super_follow_user_api_enabled" => true,
|
||||
"super_follow_tweet_api_enabled" => true,
|
||||
"articles_api_enabled" => true,
|
||||
"android_graphql_skip_api_media_color_palette" => true,
|
||||
"creator_subscriptions_tweet_preview_api_enabled" => true,
|
||||
"freedom_of_speech_not_reach_fetch_enabled" => true,
|
||||
"tweetypie_unmention_optimization_enabled" => true,
|
||||
"longform_notetweets_consumption_enabled" => true,
|
||||
"subscriptions_verification_info_enabled" => true,
|
||||
"blue_business_profile_image_shape_enabled" => true,
|
||||
"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled" => true,
|
||||
"immersive_video_status_linkable_timestamps" => true,
|
||||
"super_follow_exclusive_tweet_notifications_enabled" => true
|
||||
]),
|
||||
"variables" => json_encode([
|
||||
"nullcast" => false,
|
||||
"includeTweetImpression" => true,
|
||||
"includeHasBirdwatchNotes" => false,
|
||||
"includeEditPerspective" => false,
|
||||
"includeEditControl" => true,
|
||||
"batch_compose" => "BatchSubsequent",
|
||||
"includeCommunityTweetRelationship" => false,
|
||||
"reply" => [
|
||||
"exclude_reply_user_ids" => [],
|
||||
"in_reply_to_tweet_id" => $tweetid,
|
||||
],
|
||||
"includeTweetVisibilityNudge" => true,
|
||||
"tweet_text" => $text,
|
||||
]),
|
||||
];
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->post('2ambiU1P_BmZ_CZ1yQ8E1Q/CreateTweet', [
|
||||
'headers' => $this->twitterHeaders, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth',
|
||||
'json' => $params
|
||||
]);
|
||||
|
||||
if ($res->getStatusCode() != 200) {
|
||||
$text = "Le compte twitter ".$user->Name." a été désactivé";
|
||||
|
||||
Http::get('https://api.telegram.org/bot7036172799:AAEVZXHu4SL64VWN5c0AxM1BVxvB0-k6lT0/sendMessage?chat_id=1970698501&text=' . urlencode($text));
|
||||
|
||||
$user->enabled = false;
|
||||
$user->save();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function follow($user, $follow)
|
||||
{
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/1.1/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->post('friendships/create.json?screen_name='.$follow.'&follow=true', [
|
||||
'headers' => $this->twitterHeaders, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth' // Assurez-vous que l'authentification OAuth est incluse
|
||||
]);
|
||||
|
||||
if ($res->getStatusCode() != 200) {
|
||||
$text = "Le compte twitter ".$user->Name." a été désactivé";
|
||||
|
||||
Http::get('https://api.telegram.org/bot7036172799:AAEVZXHu4SL64VWN5c0AxM1BVxvB0-k6lT0/sendMessage?chat_id=1970698501&text=' . urlencode($text));
|
||||
|
||||
$user->enabled = false;
|
||||
$user->save();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function like($user, $tweetid)
|
||||
{
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/graphql/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
$params = [
|
||||
"variables" => [
|
||||
"includeTweetImpression" => true,
|
||||
"includeHasBirdwatchNotes" => false,
|
||||
"includeEditPerspective" => false,
|
||||
"tweet_id" => $tweetid,
|
||||
"includeEditControl" => true
|
||||
]
|
||||
];
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->post('lI07N6Otwv1PhnEgXILM7A/FavoriteTweet', [
|
||||
'headers' => $this->twitterHeaders, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth',
|
||||
'json' => $params
|
||||
]);
|
||||
|
||||
}
|
||||
public function tweet($user, $text)
|
||||
{
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/graphql/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
$params = [
|
||||
"features" => [
|
||||
"longform_notetweets_inline_media_enabled" => true,
|
||||
"super_follow_badge_privacy_enabled" => true,
|
||||
"longform_notetweets_rich_text_read_enabled" => true,
|
||||
"super_follow_user_api_enabled" => true,
|
||||
"super_follow_tweet_api_enabled" => true,
|
||||
"articles_api_enabled" => true,
|
||||
"android_graphql_skip_api_media_color_palette" => true,
|
||||
"creator_subscriptions_tweet_preview_api_enabled" => true,
|
||||
"freedom_of_speech_not_reach_fetch_enabled" => true,
|
||||
"tweetypie_unmention_optimization_enabled" => true,
|
||||
"longform_notetweets_consumption_enabled" => true,
|
||||
"subscriptions_verification_info_enabled" => true,
|
||||
"blue_business_profile_image_shape_enabled" => true,
|
||||
"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled" => true,
|
||||
"immersive_video_status_linkable_timestamps" => true,
|
||||
"super_follow_exclusive_tweet_notifications_enabled" => true
|
||||
],
|
||||
"variables" => [
|
||||
"nullcast" => false,
|
||||
"includeTweetImpression" => true,
|
||||
"includeHasBirdwatchNotes" => false,
|
||||
"includeEditPerspective" => false,
|
||||
"includeEditControl" => true,
|
||||
"includeCommunityTweetRelationship" => false,
|
||||
"includeTweetVisibilityNudge" => true,
|
||||
"tweet_text" => $text
|
||||
]
|
||||
];
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->post('2ambiU1P_BmZ_CZ1yQ8E1Q/CreateTweet', [
|
||||
'headers' => $this->twitterHeaders, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth',
|
||||
'json' => $params
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
public function unread($user)
|
||||
{
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/2/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->get('badge_count/badge_count.json?supports_ntab_urt=true', [
|
||||
'headers' => $this->twitterHeaders, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth' // Assurez-vous que l'authentification OAuth est incluse
|
||||
]);
|
||||
|
||||
|
||||
$unred = json_decode($res->getBody()->getContents(), true);
|
||||
|
||||
// L'URL des deux liens
|
||||
$url = 'https://myx.ovh/nova/resources/accounts/'.$user->id;
|
||||
|
||||
$keyboard = [
|
||||
'inline_keyboard' => [
|
||||
[
|
||||
['text' => 'Cliquez ici pour plus d\'infos', 'url' => $url]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
// Convertir le tableau de clavier en JSON
|
||||
$keyboardJson = json_encode($keyboard);
|
||||
|
||||
if ($unred['dm_unread_count'] > 0) {
|
||||
|
||||
$text = "Un nouveau message pour le compte ".$user->name;
|
||||
Http::get('https://api.telegram.org/bot6784810105:AAEq3emnkRwdyvCLC-iqdIjVJ2Ke6HwwGjg/sendMessage', [
|
||||
'chat_id' => '1970698501', // Remplacez par votre chat_id
|
||||
'text' => $text,
|
||||
'reply_markup' => $keyboardJson
|
||||
]);
|
||||
|
||||
|
||||
}elseif ($unred['ntab_unread_count'] > 0) {
|
||||
|
||||
$text = "Une notification pour le compte ".$user->name;
|
||||
Http::get('https://api.telegram.org/bot6784810105:AAEq3emnkRwdyvCLC-iqdIjVJ2Ke6HwwGjg/sendMessage', [
|
||||
'chat_id' => '1970698501', // Remplacez par votre chat_id
|
||||
'text' => $text,
|
||||
'reply_markup' => $keyboardJson
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getweets($user, $tweetid)
|
||||
{
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/graphql/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
$params = [
|
||||
'variables' => [
|
||||
'referrer' => 'home',
|
||||
'includeTweetImpression' => true,
|
||||
'includeHasBirdwatchNotes' => false,
|
||||
'isReaderMode' => false,
|
||||
'includeEditPerspective' => false,
|
||||
'includeEditControl' => true,
|
||||
'focalTweetId' => $tweetid,
|
||||
'includeCommunityTweetRelationship' => true,
|
||||
'includeTweetVisibilityNudge' => true
|
||||
],
|
||||
'features' => [
|
||||
'longform_notetweets_inline_media_enabled' => true,
|
||||
'super_follow_badge_privacy_enabled' => true,
|
||||
'longform_notetweets_rich_text_read_enabled' => true,
|
||||
'super_follow_user_api_enabled' => true,
|
||||
'unified_cards_ad_metadata_container_dynamic_card_content_query_enabled' => true,
|
||||
'super_follow_tweet_api_enabled' => true,
|
||||
'articles_api_enabled' => true,
|
||||
'android_graphql_skip_api_media_color_palette' => true,
|
||||
'creator_subscriptions_tweet_preview_api_enabled' => true,
|
||||
'freedom_of_speech_not_reach_fetch_enabled' => true,
|
||||
'tweetypie_unmention_optimization_enabled' => true,
|
||||
'longform_notetweets_consumption_enabled' => true,
|
||||
'subscriptions_verification_info_enabled' => true,
|
||||
'blue_business_profile_image_shape_enabled' => true,
|
||||
'tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled' => true,
|
||||
'immersive_video_status_linkable_timestamps' => true,
|
||||
'super_follow_exclusive_tweet_notifications_enabled' => true
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
// Initialisation du tableau des tweets à l'extérieur de la boucle
|
||||
$tweets = [];
|
||||
|
||||
// Initialisation du curseur à null avant le début de la boucle
|
||||
$cursor = null;
|
||||
|
||||
// Nombre de tours
|
||||
$maxLoops = 10;
|
||||
|
||||
// Boucle pour exécuter 5 tours
|
||||
for ($loop = 1; $loop <= $maxLoops; $loop++) {
|
||||
// Si ce n'est pas le premier tour, ajouter le curseur dans les paramètres
|
||||
if ($loop > 1 && $cursor !== null) {
|
||||
$params['variables']['cursor'] = $cursor; // Ajouter la valeur du curseur au paramètre
|
||||
}
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->get('NAHO_rBo3Yf1hBXROp7Msg/ConversationTimelineV2', [
|
||||
'headers' => $this->twitterHeaders, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth',
|
||||
'json' => $params
|
||||
]);
|
||||
|
||||
// Décoder la réponse
|
||||
$data = json_decode($res->getBody()->getContents(), true);
|
||||
|
||||
// Réinitialiser le curseur à chaque tour
|
||||
$cursor = null;
|
||||
|
||||
// Navigation dans le tableau pour extraire les données
|
||||
$instructions = $data['data']['timeline_response']['instructions'] ?? [];
|
||||
foreach ($instructions as $instruction) {
|
||||
// Vérification si l'instruction est de type 'TimelineAddEntries'
|
||||
if ($instruction['__typename'] === 'TimelineAddEntries') {
|
||||
// Parcours des entrées (entries) dans chaque instruction
|
||||
foreach ($instruction['entries'] as $entry) {
|
||||
// Vérifier si l'entrée contient un tweet
|
||||
if (isset($entry['content']['items'][0]['item']['content']['tweetResult'])) {
|
||||
// Récupérer le texte complet du tweet
|
||||
$tweets[] = $entry['content']['items'][0]['item']['content']['tweetResult']['result']['legacy']['full_text'] ?? '';
|
||||
}
|
||||
|
||||
// Vérifier si l'entrée contient un curseur, dont l'entryId commence par 'cursor-bottom'
|
||||
if (isset($entry['content']['content']['value']) && str_starts_with($entry['entryId'], 'cursor-bottom')) {
|
||||
// Récupérer la valeur du curseur
|
||||
$cursor = $entry['content']['content']['value'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $tweets;
|
||||
}
|
||||
|
||||
public function newstweet($user)
|
||||
{
|
||||
|
||||
$stack = $this->Oauth1($user);
|
||||
|
||||
$newArray = [];
|
||||
$existingConversationIds = []; // Tableau pour suivre les IDs de conversation déjà vus
|
||||
|
||||
$search = [
|
||||
'1177177387475378177',
|
||||
'1491472590891888645',
|
||||
'1642170070351638534',
|
||||
'1533089245576970240',
|
||||
'1493931667731406848',
|
||||
'1513789977938776070',
|
||||
'1531291630040391682',
|
||||
'1741188576845455676'
|
||||
];
|
||||
|
||||
foreach ($search as $list) {
|
||||
// Créer le client Guzzle avec le handler stack
|
||||
$client = new Client([
|
||||
'base_uri' => 'https://api.twitter.com/graphql/',
|
||||
'handler' => $stack,
|
||||
'proxy' => [
|
||||
'http' => 'http://xtjnmwvl-'.$user->id.':lp7iv1lq9glu@p.webshare.io:80',
|
||||
]
|
||||
]);
|
||||
|
||||
// Ajouter les en-têtes personnalisés
|
||||
$headers = [
|
||||
'User-Agent' => 'TwitterAndroid/10.46.0-release.0 (310460000-r-0) Android+SDK+built+for+x86/11 (unknown;Android+SDK+built+for+x86;Android;sdk_phone_x86;0;;1;2013)',
|
||||
'x-twitter-client-language' => 'en-US',
|
||||
'x-twitter-client-version' => '10.46.0-release.0',
|
||||
'x-twitter-client' => 'TwitterAndroid',
|
||||
'x-twitter-api-version' => '5',
|
||||
'x-twitter-active-user' => 'yes',
|
||||
'os-version' => '30',
|
||||
'x-attest-token' => 'no_token',
|
||||
];
|
||||
|
||||
$params = [
|
||||
"features" => [
|
||||
"longform_notetweets_inline_media_enabled" => true,
|
||||
"super_follow_badge_privacy_enabled" => true,
|
||||
"longform_notetweets_rich_text_read_enabled" => true,
|
||||
"super_follow_user_api_enabled" => true,
|
||||
"unified_cards_ad_metadata_container_dynamic_card_content_query_enabled" => true,
|
||||
"super_follow_tweet_api_enabled" => true,
|
||||
"articles_api_enabled" => true,
|
||||
"android_graphql_skip_api_media_color_palette" => true,
|
||||
"creator_subscriptions_tweet_preview_api_enabled" => true,
|
||||
"freedom_of_speech_not_reach_fetch_enabled" => true,
|
||||
"tweetypie_unmention_optimization_enabled" => true,
|
||||
"longform_notetweets_consumption_enabled" => true,
|
||||
"subscriptions_verification_info_enabled" => true,
|
||||
"blue_business_profile_image_shape_enabled" => true,
|
||||
"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled" => true,
|
||||
"immersive_video_status_linkable_timestamps" => true,
|
||||
"super_follow_exclusive_tweet_notifications_enabled" => true,
|
||||
],
|
||||
"variables" => [
|
||||
"includeTweetImpression" => true,
|
||||
"includeHasBirdwatchNotes" => false,
|
||||
"includeEditPerspective" => false,
|
||||
"includeEditControl" => true,
|
||||
"rest_id" => $list,
|
||||
"includeTweetVisibilityNudge" => true,
|
||||
]
|
||||
];
|
||||
|
||||
// Effectuer la requête POST avec OAuth et les en-têtes personnalisés
|
||||
$res = $client->get('LgWGBhvCVo5vHMsokMdEWA/ListTimeline', [
|
||||
'headers' => $headers, // Ajouter les en-têtes ici
|
||||
'auth' => 'oauth',
|
||||
'json' => $params
|
||||
]);
|
||||
|
||||
$data = json_decode($res->getBody()->getContents(), true);
|
||||
|
||||
$tweets = $data['data']['list']['timeline_response']['timeline']['instructions'][0]['entries'];
|
||||
|
||||
foreach ($tweets as $item) {
|
||||
if (isset($item['content']['content']['tweetResult']['result']['legacy']['retweeted_status_result'])) {
|
||||
// Tweet retweeté, ignorer
|
||||
} elseif (isset($item['content']['content']['tweetResult']['result']['legacy'])) {
|
||||
$news = $item['content']['content']['tweetResult']['result']['legacy'];
|
||||
$conversationId = $news['conversation_id_str'];
|
||||
|
||||
// Vérifier si le tweet a déjà été ajouté en fonction de l'ID de la conversation
|
||||
if (in_array($conversationId, $existingConversationIds)) {
|
||||
continue; // Si le tweet existe déjà, passer à l'itération suivante
|
||||
}
|
||||
|
||||
// Ajouter l'ID de conversation à la liste des IDs déjà vus
|
||||
$existingConversationIds[] = $conversationId;
|
||||
|
||||
// Ajouter le tweet si le nombre de réponses, de favoris ou de retweets est supérieur à 50
|
||||
if ($news['reply_count'] > 10 || $news['favorite_count'] > 10 || $news['retweet_count'] > 10) {
|
||||
$newArray[] = $news;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cache::put('news', $newArray, 1800);
|
||||
|
||||
return $newArray;
|
||||
|
||||
}
|
||||
|
||||
private function Oauth1($user)
|
||||
{
|
||||
// Créer le stack pour gérer l'authentification OAuth
|
||||
$stack = HandlerStack::create();
|
||||
|
||||
$middleware = new Oauth1([
|
||||
'consumer_key' => '3nVuSoBZnx6U4vzUxf5w',
|
||||
'consumer_secret' => 'Bcs59EFbbsdF6Sl9Ng71smgStWEGwXXKSjYvPVt7qys',
|
||||
'token' => $user->oauth_token,
|
||||
'token_secret' => $user->oauth_token_secret
|
||||
]);
|
||||
|
||||
$stack->push($middleware);
|
||||
|
||||
return $stack;
|
||||
}
|
||||
|
||||
}
|
||||
341
app/Http/Controllers/AccountController.php
Normal file
341
app/Http/Controllers/AccountController.php
Normal file
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Jobs\ProcessNews;
|
||||
use App\Models\Account;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use App\Http\Controllers\APIController;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Webklex\PHPIMAP\ClientManager;
|
||||
|
||||
class AccountController extends Controller
|
||||
{
|
||||
public function login($id)
|
||||
{
|
||||
$user = Account::find($id);
|
||||
|
||||
$username = $user->name;
|
||||
$password = $user->password;
|
||||
$email = $user->rambler_email;
|
||||
$rambler_password = $user->rambler_password;
|
||||
|
||||
$proxy = 'http://xtjnmwvl-'.$id.':lp7iv1lq9glu@p.webshare.io:80';
|
||||
|
||||
// Clés et jetons de Twitter
|
||||
$TW_CONSUMER_KEY = '3nVuSoBZnx6U4vzUxf5w';
|
||||
$TW_CONSUMER_SECRET = 'Bcs59EFbbsdF6Sl9Ng71smgStWEGwXXKSjYvPVt7qys';
|
||||
$TW_ANDROID_BASIC_TOKEN = 'Basic ' . base64_encode("$TW_CONSUMER_KEY:$TW_CONSUMER_SECRET");
|
||||
|
||||
// Requête pour obtenir le bearer token
|
||||
$response = Http::withHeaders([
|
||||
'Authorization' => $TW_ANDROID_BASIC_TOKEN,
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
])->asForm()->post('https://api.twitter.com/oauth2/token', [
|
||||
'grant_type' => 'client_credentials',
|
||||
]);
|
||||
|
||||
$bearerToken = collect($response->json())->implode(' ');
|
||||
|
||||
// Requête pour obtenir le guest token
|
||||
$curl = curl_init();
|
||||
|
||||
curl_setopt_array($curl, array(
|
||||
CURLOPT_URL => 'https://api.twitter.com/1.1/guest/activate.json',
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_ENCODING => '',
|
||||
CURLOPT_MAXREDIRS => 10,
|
||||
CURLOPT_TIMEOUT => 0,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||||
CURLOPT_CUSTOMREQUEST => 'POST',
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
'Authorization: ' . $bearerToken
|
||||
),
|
||||
));
|
||||
|
||||
$response = curl_exec($curl);
|
||||
|
||||
curl_close($curl);
|
||||
$reponse = json_decode($response, true);
|
||||
$guestToken = $reponse['guest_token'];
|
||||
|
||||
// Configuration des en-têtes pour les futures requêtes
|
||||
$twitterHeaders = [
|
||||
'Authorization' => $bearerToken,
|
||||
'User-Agent' => 'TwitterAndroid/10.46.0-release.0 (310460000-r-0) Android+SDK+built+for+x86/11 (unknown;Android+SDK+built+for+x86;Android;sdk_phone_x86;0;;1;2013)',
|
||||
'x-twitter-api-version' => '5',
|
||||
'x-twitter-client' => 'TwitterAndroid',
|
||||
'x-twitter-client-version' => '10.46.0-release.0',
|
||||
'x-twitter-active-user' => 'yes',
|
||||
'os-version' => '30',
|
||||
'x-twitter-client-language' => 'en-US',
|
||||
'x-attest-token' => 'no_token',
|
||||
'X-Guest-Token' => $guestToken,
|
||||
];
|
||||
|
||||
// Initialisation de la session avec Laravel HTTP pour le flux de connexion
|
||||
// Étape 1 : Commencer le flux de connexion
|
||||
$task1 = Http::withOptions([
|
||||
'proxy' => $proxy
|
||||
])->withHeaders($twitterHeaders)->post('https://api.twitter.com/1.1/onboarding/task.json?flow_name=login&api_version=1&known_device_token=', [
|
||||
'input_flow_data' => [
|
||||
'country_code' => null,
|
||||
'flow_context' => [
|
||||
'start_location' => [
|
||||
'location' => 'deeplink',
|
||||
],
|
||||
],
|
||||
'requested_variant' => null,
|
||||
'target_user_id' => 0,
|
||||
],
|
||||
]);
|
||||
|
||||
// Stockage de l'en-tête 'att' pour les futures requêtes
|
||||
$twitterHeaders['att'] = $task1->header('att');
|
||||
|
||||
sleep(5);
|
||||
|
||||
// Étape 2 : Saisie du nom d'utilisateur
|
||||
$task2 = Http::withOptions([
|
||||
'proxy' => $proxy
|
||||
])->withHeaders($twitterHeaders)->post('https://api.twitter.com/1.1/onboarding/task.json', [
|
||||
'flow_token' => $task1->json()['flow_token'],
|
||||
'subtask_inputs' => [
|
||||
[
|
||||
'enter_text' => [
|
||||
'text' => $username,
|
||||
'link' => 'next_link',
|
||||
],
|
||||
'subtask_id' => 'LoginEnterUserIdentifier',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
sleep(5);
|
||||
|
||||
if ($task2->json()['subtasks'][0]['subtask_id'] === 'LoginEnterAlternateIdentifierSubtask') {
|
||||
$task2bis = Http::withOptions([
|
||||
'proxy' => $proxy
|
||||
])->withHeaders($twitterHeaders)->post('https://api.twitter.com/1.1/onboarding/task.json', [
|
||||
'flow_token' => $task2->json()['flow_token'],
|
||||
'subtask_inputs' => [
|
||||
[
|
||||
'enter_text' => [
|
||||
'text' => $email,
|
||||
'link' => 'next_link',
|
||||
],
|
||||
'subtask_id' => 'LoginEnterAlternateIdentifierSubtask',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$task2 = $task2bis;
|
||||
}
|
||||
|
||||
sleep(5);
|
||||
|
||||
// Étape 3 : Saisie du mot de passe
|
||||
$task3 = Http::withOptions([
|
||||
'proxy' => $proxy
|
||||
])->withHeaders($twitterHeaders)->post('https://api.twitter.com/1.1/onboarding/task.json', [
|
||||
'flow_token' => $task2->json()['flow_token'],
|
||||
'subtask_inputs' => [
|
||||
[
|
||||
'enter_password' => [
|
||||
'password' => $password,
|
||||
'link' => 'next_link',
|
||||
],
|
||||
'subtask_id' => 'LoginEnterPassword',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
if ($task3->json()['subtasks'][0]['subtask_id'] === 'LoginAcid') {
|
||||
sleep(5);
|
||||
if(isset($task3->json()['subtasks'][0]['enter_text']['hint_text'])){
|
||||
$code = $this->getCodeFromLastEmail($email, $rambler_password);
|
||||
$task3bis = Http::withOptions([
|
||||
'proxy' => $proxy
|
||||
])->withHeaders($twitterHeaders)->post('https://api.twitter.com/1.1/onboarding/task.json', [
|
||||
'flow_token' => $task3->json()['flow_token'],
|
||||
'subtask_inputs' => [
|
||||
[
|
||||
'enter_text' => [
|
||||
'text' => $code,
|
||||
'link' => 'next_link',
|
||||
],
|
||||
'subtask_id' => 'LoginAcid',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}else{
|
||||
$task3bis = Http::withOptions([
|
||||
'proxy' => $proxy
|
||||
])->withHeaders($twitterHeaders)->post('https://api.twitter.com/1.1/onboarding/task.json', [
|
||||
'flow_token' => $task3->json()['flow_token'],
|
||||
'subtask_inputs' => [
|
||||
[
|
||||
'enter_text' => [
|
||||
'text' => $email,
|
||||
'link' => 'next_link',
|
||||
],
|
||||
'subtask_id' => 'LoginAcid',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
$task3 = $task3bis;
|
||||
}
|
||||
|
||||
if($task3->json()['subtasks'][0]['subtask_id'] === 'LoginEnterOtp'){
|
||||
$code = $this->getCodeFromLastEmail($email, $rambler_password);
|
||||
$task3bis = Http::withOptions([
|
||||
'proxy' => $proxy
|
||||
])->withHeaders($twitterHeaders)->post('https://api.twitter.com/1.1/onboarding/task.json', [
|
||||
'flow_token' => $task3->json()['flow_token'],
|
||||
'subtask_inputs' => [
|
||||
[
|
||||
'enter_text' => [
|
||||
'text' => $code,
|
||||
'link' => 'next_link',
|
||||
],
|
||||
'subtask_id' => 'LoginEnterOtp',
|
||||
],
|
||||
],
|
||||
]);
|
||||
$task3 = $task3bis;
|
||||
}
|
||||
|
||||
if($task3->json()['subtasks']['0']['subtask_id'] == 'LoginSuccessSubtask' ){
|
||||
$user->update([
|
||||
'oauth_token' => $task3->json()['subtasks']['0']['open_account']['oauth_token'],
|
||||
'oauth_token_secret' => $task3->json()['subtasks']['0']['open_account']['oauth_token_secret'],
|
||||
'known_device_token' => $task3->json()['subtasks']['0']['open_account']['known_device_token'],
|
||||
'enable' => true,
|
||||
]);
|
||||
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private function getCodeFromLastEmail($email, $password)
|
||||
{
|
||||
// Attendre 15 secondes avant de vérifier les emails
|
||||
sleep(15);
|
||||
|
||||
// Configurer le client IMAP de manière dynamique
|
||||
$clientManager = new ClientManager();
|
||||
|
||||
$client = $clientManager->make([
|
||||
'host' => 'imap.rambler.ru',
|
||||
'port' => '993',
|
||||
'encryption' => 'ssl',
|
||||
'validate_cert' => true,
|
||||
'username' => $email,
|
||||
'password' => $password,
|
||||
'protocol' => 'imap'
|
||||
]);
|
||||
|
||||
// Se connecter au compte
|
||||
$client->connect();
|
||||
|
||||
// Sélectionner la boîte de réception
|
||||
$folder = $client->getFolder('INBOX');
|
||||
|
||||
// Récupérer le dernier email de l'expéditeur "verify@x.com"
|
||||
$messages = $folder->messages()->all()->get();
|
||||
$count = count($messages);
|
||||
$message = $messages[$count - 1];
|
||||
|
||||
if ($message) {
|
||||
// Vérifier le titre de l'email
|
||||
$subject = $message->getSubject();
|
||||
|
||||
// Chercher le code dans le sujet
|
||||
if (preg_match('/Your X confirmation code is (\w+)/', $subject, $matches)) {
|
||||
return $matches[1]; // Retourner le code trouvé dans le titre
|
||||
}
|
||||
|
||||
// Si aucun code trouvé dans le sujet, vérifier le corps du mail
|
||||
$body = $message->getTextBody();
|
||||
if (preg_match('/\b(\d{6})\b/', $body, $matches)) {
|
||||
return $matches[1]; // Retourner le code trouvé dans le corps
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function tweetnews()
|
||||
{
|
||||
// Vérifier si la queue est vide (en fonction de votre driver)
|
||||
$queue = Queue::getDefaultDriver(); // Par défaut, c'est 'default'
|
||||
|
||||
$jobsCount = Queue::size($queue);
|
||||
|
||||
if ($jobsCount === 0) {
|
||||
|
||||
$accounts = Account::where('enable', true)->get();
|
||||
|
||||
foreach($accounts as $user){
|
||||
|
||||
$API = new APIController();
|
||||
|
||||
//On check les notifs
|
||||
$API->unread($user);
|
||||
|
||||
if (Cache::has('news')) {
|
||||
$news = Cache::get('news');
|
||||
}else{
|
||||
$news = $API->newstweet($user);
|
||||
}
|
||||
|
||||
shuffle($news);
|
||||
|
||||
$nb = rand(1,3);
|
||||
|
||||
if (count($news) >= $nb) {
|
||||
$selectedArticles = array_slice($news, 0, $nb);
|
||||
|
||||
foreach ($selectedArticles as $article) {
|
||||
|
||||
$tweetid = $article['conversation_id_str'];
|
||||
$API->retweet($user, $tweetid);
|
||||
sleep(15);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public
|
||||
function auto($contestId)
|
||||
{
|
||||
$contest = Contest::find($contestId);
|
||||
|
||||
if (!$contest) {
|
||||
session()->flash('error', 'Concours introuvable.');
|
||||
return;
|
||||
}
|
||||
|
||||
flash()->success('Concours ' . $contest->name . ' en cours de participation');
|
||||
|
||||
// Récupération des comptes activés
|
||||
$accounts = Account::where('enable', true)->get();
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
ProcessTweet::dispatch($contest->id, $account->id); // Envoi du tweet pour participer
|
||||
}
|
||||
|
||||
// Mise à jour du concours pour indiquer qu'il a été participé
|
||||
$contest->participated = true;
|
||||
$contest->save();
|
||||
|
||||
// Recharger les concours
|
||||
$this->resetPage(); // Reset pagination to the first page
|
||||
}
|
||||
}
|
||||
118
app/Http/Controllers/BotController.php
Normal file
118
app/Http/Controllers/BotController.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\TwitterController;
|
||||
use App\Models\Account;
|
||||
use App\Models\Block;
|
||||
use App\Models\Concour;
|
||||
use App\Models\Contest;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Laravel\Dusk\Browser;
|
||||
use Symfony\Component\BrowserKit\HttpBrowser;
|
||||
use Symfony\Component\HttpClient\HttpClient;
|
||||
use Illuminate\Http\Request;
|
||||
use Throwable;
|
||||
|
||||
class BotController extends Controller
|
||||
{
|
||||
|
||||
public function getSpecialComment($user,$id){
|
||||
|
||||
$user = Account::find($user);
|
||||
|
||||
$API = new APIController();
|
||||
|
||||
// On check les notifs
|
||||
$texts = $API->getweets($user, $id);
|
||||
|
||||
// Filtrer les phrases vides
|
||||
$texts = array_filter($texts, function($phrase) {
|
||||
return !empty(trim($phrase)); // Ignore les chaînes vides ou contenant uniquement des espaces
|
||||
});
|
||||
|
||||
// Initialiser un tableau pour stocker les occurrences des phrases
|
||||
$occurrences = [];
|
||||
|
||||
foreach ($texts as $index1 => $phrase1) {
|
||||
foreach ($texts as $index2 => $phrase2) {
|
||||
if ($index1 !== $index2) {
|
||||
$similarity = $this->cosineSimilarity($phrase1, $phrase2);
|
||||
// Vous pouvez ajuster le seuil de similarité en fonction de vos besoins
|
||||
if ($similarity > 0.5) {
|
||||
// Incrémenter le compteur pour les deux phrases
|
||||
$occurrences[$index1] = isset($occurrences[$index1]) ? $occurrences[$index1] + 1 : 1;
|
||||
$occurrences[$index2] = isset($occurrences[$index2]) ? $occurrences[$index2] + 1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trouver l'index de la phrase avec le comptage le plus élevé
|
||||
$indexPhrasePlusFrequente = (!empty($occurrences)) ? array_search(max($occurrences), $occurrences) : null;
|
||||
|
||||
// Récupérer la phrase avec le comptage le plus élevé
|
||||
$phrasePlusFrequente = ($indexPhrasePlusFrequente !== null) ? $texts[$indexPhrasePlusFrequente] : null;
|
||||
|
||||
if ($phrasePlusFrequente != null) {
|
||||
// Supprimer les hashtags
|
||||
$phrasePlusFrequente = preg_replace('/#\w+\s?/', '', $phrasePlusFrequente);
|
||||
|
||||
// Supprimer les tags
|
||||
$phrasePlusFrequente = preg_replace('/@\w+\s?/', '', $phrasePlusFrequente);
|
||||
|
||||
// Supprimer les emojis
|
||||
$phrasePlusFrequente = $this->remove_emojis($phrasePlusFrequente);
|
||||
|
||||
return $phrasePlusFrequente;
|
||||
} else {
|
||||
$tweetcomments = config('twitter.sentence_for_random_comment');
|
||||
return Arr::random($tweetcomments);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function cosineSimilarity($text1, $text2)
|
||||
{
|
||||
$words1 = str_word_count(strtolower($text1), 1);
|
||||
$words2 = str_word_count(strtolower($text2), 1);
|
||||
|
||||
$allWords = array_unique(array_merge($words1, $words2));
|
||||
$vector1 = $vector2 = [];
|
||||
|
||||
// Construire les vecteurs avec les fréquences des mots
|
||||
foreach ($allWords as $word) {
|
||||
$vector1[] = in_array($word, $words1) ? 1 : 0;
|
||||
$vector2[] = in_array($word, $words2) ? 1 : 0;
|
||||
}
|
||||
|
||||
$dotProduct = 0;
|
||||
|
||||
// Calculer le produit scalaire des vecteurs
|
||||
for ($i = 0; $i < count($allWords); $i++) {
|
||||
$dotProduct += $vector1[$i] * $vector2[$i];
|
||||
}
|
||||
|
||||
$magnitude1 = sqrt(array_sum($vector1));
|
||||
$magnitude2 = sqrt(array_sum($vector2));
|
||||
|
||||
if ($magnitude1 * $magnitude2 == 0) {
|
||||
return 0; // Pour éviter une division par zéro
|
||||
}
|
||||
|
||||
return $dotProduct / ($magnitude1 * $magnitude2);
|
||||
}
|
||||
|
||||
private function remove_emojis($string)
|
||||
{
|
||||
// Match all emojis (including extended ones)
|
||||
$regex_emojis = '/[\x{1F600}-\x{1F64F}\x{1F300}-\x{1F5FF}\x{1F680}-\x{1F6FF}\x{1F900}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}]/u';
|
||||
$clear_string = preg_replace($regex_emojis, '', $string);
|
||||
|
||||
return $clear_string;
|
||||
}
|
||||
|
||||
}
|
||||
521
app/Http/Controllers/ContestController.php
Normal file
521
app/Http/Controllers/ContestController.php
Normal file
@@ -0,0 +1,521 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Block;
|
||||
use App\Models\Contest;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Symfony\Component\BrowserKit\HttpBrowser;
|
||||
use Symfony\Component\HttpClient\HttpClient;
|
||||
|
||||
class ContestController extends Controller
|
||||
{
|
||||
public function twitterlist()
|
||||
{
|
||||
$client = new HttpBrowser(HttpClient::create(['verify_peer' => false, 'verify_host' => false, 'timeout' => '60']));
|
||||
|
||||
// Création des informations d'authentification
|
||||
$username = 'MyX';
|
||||
$password = '@Gaudin95';
|
||||
$credentials = base64_encode("$username:$password");
|
||||
|
||||
// Ajout des informations d'authentification à l'en-tête de la demande HTTP
|
||||
$client->setServerParameter('HTTP_AUTHORIZATION', 'Basic ' . $credentials);
|
||||
$client->setServerParameter('HTTP_USER_AGENT', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36');
|
||||
$crawler = $client->request('GET', 'https://nitter-myx.fly.dev/i/lists/1686126753205387264');
|
||||
|
||||
$i = 1;
|
||||
|
||||
while ($i < 50){
|
||||
$results = $crawler->filterXPath('//div[@class="timeline-item "]')->each(function ($node) {
|
||||
$id = ($node->filterXPath('//*[@class="tweet-link"]'))->attr('href');
|
||||
$created_at = ($node->filterXPath('//span[@class="tweet-date"]/a'))->attr('title');
|
||||
$text = ($node->filterXPath('//*[@class="tweet-content media-body"]'))->text();
|
||||
$screen = ($node->filterXPath('//a[@class="username"]'))->text();
|
||||
$fullname = ($node->filterXPath('//a[@class="fullname"]'))->text();
|
||||
$imageNode = $node->filterXPath('//a[@class="still-image"]');
|
||||
$nbretweet = ($node->filterXPath('//*[@class="tweet-stat"][2]'))->text();
|
||||
$nbretweet = str_replace(',', '', $nbretweet);
|
||||
$nblike = ($node->filterXPath('//*[@class="tweet-stat"][4]'))->text();
|
||||
$nblike = str_replace(',', '', $nblike);
|
||||
$nbreply = ($node->filterXPath('//*[@class="tweet-stat"][1]'))->text();
|
||||
$nbreply = str_replace(',', '', $nbreply);
|
||||
|
||||
//Modifications
|
||||
if ($imageNode->count() > 0) {
|
||||
$picture = $imageNode->attr('href');
|
||||
$picture = urldecode($picture);
|
||||
$picture = str_replace('/pic/orig/', 'https://pbs.twimg.com/', $picture);
|
||||
}else{
|
||||
$picture = null;
|
||||
}
|
||||
|
||||
$screen = str_replace('@', '', $screen);
|
||||
$id = str_replace('/'.$screen.'/status/', '', $id);
|
||||
$id = str_replace('#m', '', $id);
|
||||
|
||||
$contest = Contest::where('tweetid', $id)->first();
|
||||
$fake = Block::where('screen_name', $screen)->first();
|
||||
$containsBlacklistedWord = preg_match('/' . implode('|', array_map('preg_quote', config('twitter.giveaway_to_blacklist'), ['/'])) . '/i', $text) === 1;
|
||||
|
||||
if(!$contest && !$fake && $nbretweet > 100 && $containsBlacklistedWord !== true) {
|
||||
$regex_detect_rts =
|
||||
[
|
||||
"/\bRT\b/",
|
||||
"/RETWEET/i",
|
||||
"/REPUBL/i",
|
||||
"/REPOST/i",
|
||||
];
|
||||
foreach ($regex_detect_rts as $regex_detect_rt) {
|
||||
//if (strstr($string, $url)) { // mine version
|
||||
preg_match($regex_detect_rt, $text, $invites);
|
||||
if (isset($invites[0])) {
|
||||
$rt = true;
|
||||
}
|
||||
}
|
||||
|
||||
//On verifie que si RT
|
||||
if (isset($rt)) {
|
||||
$inputs = array();
|
||||
//On recherche la date de fin du concours
|
||||
$date = $this->getDate($text);
|
||||
if ($date != null) {
|
||||
$fin = $date;
|
||||
} else {
|
||||
$fin = $this->getTwitterDate($created_at);
|
||||
}
|
||||
//On recherche la date de fin du concours
|
||||
if ($fin >= Carbon::now()->format('Y-m-d')) {
|
||||
|
||||
Contest::create([
|
||||
'name' => $fullname,
|
||||
'screen' => $screen,
|
||||
'description' => $text,
|
||||
'url' => 'https://x.com/'.$screen.'/status/'.$id,
|
||||
'picture' => $picture,
|
||||
'tweetid' => $id,
|
||||
'fin' => $fin,
|
||||
'nbretweet' => $nbretweet,
|
||||
'nblike' => $nblike,
|
||||
'nbreply' => $nbreply,
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
$nextPageButton = $crawler->filterXPath('//div[@class="show-more"]/a')->link();
|
||||
$url = $nextPageButton->getUri();
|
||||
$crawler = $client->request('GET', $url);
|
||||
$i++;
|
||||
}
|
||||
|
||||
$reponse = $client->getResponse();
|
||||
var_dump($reponse);
|
||||
|
||||
echo 'Fait !';
|
||||
|
||||
}
|
||||
|
||||
public function searchcontest()
|
||||
{
|
||||
$search = [
|
||||
'giveaway',
|
||||
'#concours',
|
||||
'concours like',
|
||||
'concours rt',
|
||||
'concours follow',
|
||||
'#JeuConcours',
|
||||
'JeuConcours',
|
||||
'jeu concours',
|
||||
'offre follow gagnant',
|
||||
'concours pour gagner',
|
||||
'gagner rt',
|
||||
'Gagnez rt follow',
|
||||
'RT follow',
|
||||
'concours rt like',
|
||||
'concours rt fav',
|
||||
'RT tweet Follow',
|
||||
'concours rt follow',
|
||||
'rt follow tas',
|
||||
'rt follow tirage au sort',
|
||||
'rt follow gagner',
|
||||
'rt follow commente',
|
||||
'rt suivre concours',
|
||||
'rt suivez concours',
|
||||
'rt suivre tirage au sort',
|
||||
'rt suivre tas',
|
||||
'concours remporter',
|
||||
'remporter rt',
|
||||
'concours tas le',
|
||||
'concours résultats le rt',
|
||||
'tirage au sort concours',
|
||||
'concours résultat le rt'
|
||||
];
|
||||
|
||||
$k = array_rand($search);
|
||||
$phrase = $search[$k];
|
||||
|
||||
$date = Carbon::now()->subDays(2)->format('Y-m-d');
|
||||
|
||||
$url = 'https://nitter-myx.fly.dev/search?f=tweets&q='.urlencode('min_replies:100 '.$phrase).'&e-nativeretweets=on&e-replies=on&&since='.$date;
|
||||
|
||||
$client = new HttpBrowser(HttpClient::create(['verify_peer' => false, 'verify_host' => false, 'timeout' => '60']));
|
||||
|
||||
// Création des informations d'authentification
|
||||
$username = 'MyX';
|
||||
$password = '@Gaudin95';
|
||||
$credentials = base64_encode("$username:$password");
|
||||
|
||||
// Ajout des informations d'authentification à l'en-tête de la demande HTTP
|
||||
$client->setServerParameter('HTTP_AUTHORIZATION', 'Basic ' . $credentials);
|
||||
$client->setServerParameter('HTTP_USER_AGENT', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36');
|
||||
$crawler = $client->request('GET', $url);
|
||||
|
||||
$crawler->filterXPath('//div[@class="timeline-item "]')->each(function ($node) {
|
||||
$id = ($node->filterXPath('//*[@class="tweet-link"]'))->attr('href');
|
||||
$created_at = ($node->filterXPath('//span[@class="tweet-date"]/a'))->attr('title');
|
||||
$text = ($node->filterXPath('//*[@class="tweet-content media-body"]'))->text();
|
||||
$screen = ($node->filterXPath('//a[@class="username"]'))->text();
|
||||
$fullname = ($node->filterXPath('//a[@class="fullname"]'))->text();
|
||||
$imageNode = $node->filterXPath('//a[@class="still-image"]');
|
||||
$nbretweet = ($node->filterXPath('//*[@class="tweet-stat"][2]'))->text();
|
||||
$nbretweet = str_replace(',', '', $nbretweet);
|
||||
$nblike = ($node->filterXPath('//*[@class="tweet-stat"][4]'))->text();
|
||||
$nblike = str_replace(',', '', $nblike);
|
||||
$nbreply = ($node->filterXPath('//*[@class="tweet-stat"][1]'))->text();
|
||||
$nbreply = str_replace(',', '', $nbreply);
|
||||
|
||||
//Modifications
|
||||
if ($imageNode->count() > 0) {
|
||||
$picture = $imageNode->attr('href');
|
||||
$picture = urldecode($picture);
|
||||
$picture = str_replace('/pic/orig/', 'https://pbs.twimg.com/', $picture);
|
||||
} else {
|
||||
$picture = null;
|
||||
}
|
||||
|
||||
$screen = str_replace('@', '', $screen);
|
||||
$id = str_replace('/' . $screen . '/status/', '', $id);
|
||||
$id = str_replace('#m', '', $id);
|
||||
|
||||
$contest = Contest::where('tweetid', $id)->first();
|
||||
$fake = Block::where('screen_name', $screen)->first();
|
||||
$containsBlacklistedWord = preg_match('/' . implode('|', array_map('preg_quote', config('twitter.giveaway_to_blacklist'), ['/'])) . '/i', $text) === 1;
|
||||
|
||||
if (!$contest && !$fake && $nbretweet > 1000 && $containsBlacklistedWord !== true) {
|
||||
|
||||
$regex_detect_rts =
|
||||
[
|
||||
"/\bRT\b/",
|
||||
"/RETWEET/i",
|
||||
"/REPUBL/i",
|
||||
"/REPOST/i",
|
||||
"/LIKE/i",
|
||||
"/MENTION/i",
|
||||
];
|
||||
|
||||
foreach ($regex_detect_rts as $regex_detect_rt) {
|
||||
//if (strstr($string, $url)) { // mine version
|
||||
preg_match($regex_detect_rt, $text, $invites);
|
||||
if (isset($invites[0])) {
|
||||
$rt = true;
|
||||
}
|
||||
}
|
||||
|
||||
//On verifie que si RT
|
||||
if (isset($rt)) {
|
||||
$inputs = array();
|
||||
//On recherche la date de fin du concours
|
||||
$date = $this->getDate($text);
|
||||
if ($date != null) {
|
||||
$fin = $date;
|
||||
} else {
|
||||
$fin = $this->getTwitterDate($created_at);
|
||||
}
|
||||
//On recherche la date de fin du concours
|
||||
if ($fin >= Carbon::now()->format('Y-m-d')) {
|
||||
|
||||
Contest::create([
|
||||
'name' => $fullname,
|
||||
'screen' => $screen,
|
||||
'description' => $text,
|
||||
'url' => 'https://x.com/' . $screen . '/status/' . $id,
|
||||
'picture' => $picture,
|
||||
'tweetid' => $id,
|
||||
'fin' => $fin,
|
||||
'nbretweet' => $nbretweet,
|
||||
'nblike' => $nblike,
|
||||
'nbreply' => $nbreply,
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
$reponse = $client->getResponse();
|
||||
var_dump($reponse);
|
||||
|
||||
echo 'Fait !';
|
||||
|
||||
}
|
||||
|
||||
public function import()
|
||||
{
|
||||
|
||||
$response = Http::get('https://rtandfollow.com/apibot');
|
||||
$tweets = $response->json();
|
||||
|
||||
foreach($tweets as $status) {
|
||||
|
||||
$tweetid = $status['tweetid'];
|
||||
$screen_name = $status['organizer']['screen_name'];
|
||||
$text = $status['description'];
|
||||
|
||||
$concours = Contest::where('tweetid', $tweetid)->first();
|
||||
$blocking = Block::where('screen_name', $screen_name)->first();
|
||||
$containsBlacklistedWord = preg_match('/' . implode('|', array_map('preg_quote', config('twitter.giveaway_to_blacklist'), ['/'])) . '/i', $text) === 1;
|
||||
|
||||
//On verifie que le concours n'est pas dans la BDD ou que l'utilisateur n'est pas bloqué
|
||||
if (empty($concours) and empty($blocking) and $containsBlacklistedWord !== true) {
|
||||
|
||||
//On recherche la date de fin du concours
|
||||
$fin = $status['fin'];
|
||||
|
||||
if ($fin >= Carbon::now()->format('Y-m-d')) {
|
||||
Contest::create([
|
||||
'name' => $status['organizer']['name'],
|
||||
'screen' => $screen_name,
|
||||
'description' => $text,
|
||||
'url' => $status['url'],
|
||||
'picture' => '',
|
||||
'tweetid' => $tweetid,
|
||||
'fin' => $fin,
|
||||
'nbretweet' => $status['nbretweet'],
|
||||
'nblike' => $status['nblike'],
|
||||
'nbreply' => $status['nbreply'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getOrganizer($screen)
|
||||
{
|
||||
$organiser = Organizer::where('screen_name', $screen)->first();
|
||||
|
||||
if ($organiser){
|
||||
return $organiser->id;
|
||||
}else
|
||||
{
|
||||
$client = new HttpBrowser(HttpClient::create(['verify_peer' => false, 'verify_host' => false, 'timeout' => '60']));
|
||||
// Création des informations d'authentification
|
||||
$username = 'autokdo';
|
||||
$password = '@Gaudin95';
|
||||
$credentials = base64_encode("$username:$password");
|
||||
|
||||
// Ajout des informations d'authentification à l'en-tête de la demande HTTP
|
||||
$client->setServerParameter('HTTP_AUTHORIZATION', 'Basic ' . $credentials);
|
||||
$client->setServerParameter('HTTP_USER_AGENT', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36');
|
||||
$crawler = $client->request('GET', 'https://nitter-autokdo.fly.dev/'.$screen);
|
||||
try{
|
||||
$name = $crawler->filterXPath('//*[@class="profile-card-fullname"]')->text();
|
||||
$description = $crawler->filterXPath('//*[@class="profile-bio"]')->text();
|
||||
$profileUrl = $crawler->getUri();
|
||||
$parsedUrl = parse_url($profileUrl);
|
||||
$baseTwitterUrl = $parsedUrl['scheme'] . '://' . $parsedUrl['host'];
|
||||
|
||||
|
||||
$image = $crawler->filterXPath('//meta[@property="og:image"]')->attr('content');
|
||||
$url = str_replace("http://nitter-autokdo.fly.dev/pic/", "", $image);
|
||||
$url = urldecode($url);
|
||||
$url = 'https://'.$url;
|
||||
$response = Http::get($url);
|
||||
$contents = $response->body();
|
||||
|
||||
// Utilisation de getimagesize pour obtenir les informations sur l'image
|
||||
$imageInfo = getimagesizefromstring($contents);
|
||||
|
||||
if ($imageInfo === false) {
|
||||
$filename = 'icon-96x96.png';
|
||||
}
|
||||
|
||||
$format = image_type_to_extension($imageInfo[2], false);
|
||||
$filename = uniqid() . '.' . $format;
|
||||
|
||||
// Stocker l'image dans le répertoire 'ads' du stockage
|
||||
Storage::put('/public/logo/'.$filename, $contents);
|
||||
|
||||
$organiser = Organizer::create([
|
||||
'name' => $name,
|
||||
'screen_name' => $screen,
|
||||
'description' => $description,
|
||||
'logo' => $filename,
|
||||
'url' => 'https://twitter.com/'.$screen,
|
||||
]);
|
||||
|
||||
return $organiser->id;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
dd($e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private function getCategorie($data)
|
||||
{
|
||||
$client = new HttpBrowser(HttpClient::create(['verify_peer' => false, 'verify_host' => false, 'timeout' => '60']));
|
||||
$client->request('GET', 'https://api.uclassify.com/v1/twittercontests/categories/classify/?readKey=c7ivTcoN2ycU&text='.$data);
|
||||
|
||||
$json = $client->getResponse()->getContent();
|
||||
|
||||
$array = json_decode($json,true);
|
||||
|
||||
$laravelArray = collect($array);
|
||||
|
||||
$laravelArray = $laravelArray->sortDesc();
|
||||
|
||||
$value = $laravelArray->first();
|
||||
|
||||
if($value < '0.5'){
|
||||
$categorie = '20';
|
||||
}
|
||||
else{
|
||||
|
||||
$cat = $laravelArray->keys()->first();
|
||||
|
||||
if($cat == 'argent'){
|
||||
$categorie = '1';
|
||||
}elseif($cat == 'beaute'){
|
||||
$categorie = '2';
|
||||
}elseif($cat == 'console'){
|
||||
$categorie = '3';
|
||||
}elseif($cat == 'cuisine'){
|
||||
$categorie = '4';
|
||||
}elseif($cat == 'dvd'){
|
||||
$categorie = '5';
|
||||
}elseif($cat == 'enfant'){
|
||||
$categorie = '6';
|
||||
}elseif($cat == 'goodies'){
|
||||
$categorie = '7';
|
||||
}elseif($cat == 'invitation'){
|
||||
$categorie = '8';
|
||||
}elseif($cat == 'livre'){
|
||||
$categorie = '9';
|
||||
}elseif($cat == 'maison'){
|
||||
$categorie = '10';
|
||||
}elseif($cat == 'mode'){
|
||||
$categorie = '11';
|
||||
}elseif($cat == 'pc'){
|
||||
$categorie = '12';
|
||||
}elseif($cat == 'sport'){
|
||||
$categorie = '13';
|
||||
}elseif($cat == 'telephone'){
|
||||
$categorie = '14';
|
||||
}elseif($cat == 'voiture'){
|
||||
$categorie = '15';
|
||||
}elseif($cat == 'voyage'){
|
||||
$categorie = '16';
|
||||
}else{
|
||||
$categorie = '20';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $categorie;
|
||||
|
||||
}
|
||||
|
||||
private function getDate($string) {
|
||||
// Pattern pour détecter les dates au format JJ/MM ou JJ.MM
|
||||
$pattern_jjmm = '/\b(\d{1,2})(\/|\.)\d{1,2}\b/';
|
||||
|
||||
// Pattern pour détecter les dates du style "1 août" (ou autre mois en français)
|
||||
$mois_fr = array(
|
||||
'janvier', 'février', 'mars', 'avril', 'mai', 'juin',
|
||||
'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'
|
||||
);
|
||||
$pattern_jj_mois_fr = '/\b(\d{1,2}) (' . implode('|', $mois_fr) . ')\b/i';
|
||||
|
||||
// Stocker les correspondances dans un tableau
|
||||
$correspondances = [];
|
||||
|
||||
// Chercher les dates au format JJ/MM ou JJ.MM
|
||||
if (preg_match_all($pattern_jjmm, $string, $matches)) {
|
||||
$correspondances = array_merge($correspondances, $matches[0]);
|
||||
}
|
||||
|
||||
// Chercher les dates du style "1 août" (ou autre mois en français)
|
||||
if (preg_match_all($pattern_jj_mois_fr, $string, $matches)) {
|
||||
// Convertir le mois en format numérique (1 pour janvier, 2 pour février, etc.)
|
||||
$mois_numerique = array_flip($mois_fr);
|
||||
foreach ($matches[2] as $index => $mois) {
|
||||
$matches[0][$index] = $matches[1][$index] . '/' . str_pad($mois_numerique[strtolower($mois)] + 1, 2, '0', STR_PAD_LEFT);
|
||||
}
|
||||
$correspondances = array_merge($correspondances, $matches[0]);
|
||||
}
|
||||
|
||||
// Vérifier s'il y a des dates détectées
|
||||
if (empty($correspondances)) {
|
||||
return ""; // Retourne une chaîne vide si aucune date n'est trouvée
|
||||
}
|
||||
|
||||
// Récupérer la dernière date détectée
|
||||
$derniere_date = end($correspondances);
|
||||
|
||||
// Convertir la dernière date au format "Y-m-d" (année-mois-jour)
|
||||
if (strpos($derniere_date, '/') !== false) {
|
||||
// Format JJ/MM
|
||||
list($jour, $mois) = explode('/', $derniere_date);
|
||||
$annee = date('Y');
|
||||
} elseif (strpos($derniere_date, '.') !== false) {
|
||||
// Format JJ.MM
|
||||
list($jour, $mois) = explode('.', $derniere_date);
|
||||
$annee = date('Y');
|
||||
} else {
|
||||
return ""; // Cas inattendu (ne devrait pas se produire)
|
||||
}
|
||||
|
||||
// Convertir en date avec gestion des erreurs (ex. : février 30)
|
||||
try {
|
||||
$date_convertie = date('Y-m-d', strtotime("$annee-$mois-$jour"));
|
||||
} catch (Exception $e) {
|
||||
return ""; // Retourne une chaîne vide si la conversion échoue
|
||||
}
|
||||
|
||||
return $date_convertie;
|
||||
}
|
||||
|
||||
private function getTwitterDate($text)
|
||||
{
|
||||
// Utilisez une expression régulière pour extraire toutes les dates
|
||||
$pattern = '/(\w{3} \d{1,2}, \d{4})/';
|
||||
preg_match_all($pattern, $text, $matches);
|
||||
|
||||
if (!empty($matches[1])) {
|
||||
// Récupérer la dernière date trouvée
|
||||
$lastDateString = end($matches[1]);
|
||||
|
||||
// Analyse de la date
|
||||
$date = Carbon::createFromFormat('M d, Y', $lastDateString);
|
||||
|
||||
// Obtenez la date au format Y-m-d
|
||||
$formattedDate = $date->addDays(1)->format('Y-m-d');
|
||||
|
||||
return $formattedDate;
|
||||
} else {
|
||||
// Retourne la date actuelle +1 jour si aucune date n'est trouvée
|
||||
return Carbon::now()->addDays(1)->format('Y-m-d');
|
||||
}
|
||||
}
|
||||
}
|
||||
27
app/Http/Controllers/HomeController.php
Normal file
27
app/Http/Controllers/HomeController.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Contest;
|
||||
use Artesaos\SEOTools\Facades\SEOTools;
|
||||
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
SEOTools::setTitle('Liste des concours');
|
||||
|
||||
return view('index');
|
||||
}
|
||||
|
||||
public function history()
|
||||
{
|
||||
|
||||
$contests = Contest::where('participated',true)->orderby('updated_at','desc')->paginate(20);
|
||||
|
||||
SEOTools::setTitle('Mon historique');
|
||||
|
||||
return view('history', compact('contests'));
|
||||
}
|
||||
}
|
||||
81
app/Jobs/ProcessNews.php
Normal file
81
app/Jobs/ProcessNews.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
use App\Http\Controllers\APIController;
|
||||
use App\Models\Account;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class ProcessNews implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
private $authid;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct($authid)
|
||||
{
|
||||
$this->authid= $authid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$API = new APIController();
|
||||
|
||||
$user = Account::find($this->authid);
|
||||
|
||||
try{
|
||||
$API->unread($user);
|
||||
|
||||
if (Cache::has('news')) {
|
||||
$news = Cache::get('news');
|
||||
}else{
|
||||
$news = $API->newstweet($user);
|
||||
}
|
||||
|
||||
shuffle($news);
|
||||
|
||||
$nb = rand(1,3);
|
||||
|
||||
if (count($news) >= $nb) {
|
||||
$selectedArticles = array_slice($news, 0, $nb);
|
||||
|
||||
foreach ($selectedArticles as $article) {
|
||||
$tweetid = $article['conversation_id_str'];
|
||||
$API->retweet($user, $tweetid);
|
||||
sleep(15);
|
||||
}
|
||||
}
|
||||
}catch (Exception $exception){
|
||||
$text = "Le compte Twitter " . $user->name . " : " . $exception->getMessage();
|
||||
|
||||
// L'URL des deux liens
|
||||
$url = 'https://myx.ovh/nova/resources/accounts/'.$user->id;
|
||||
|
||||
$keyboard = [
|
||||
'inline_keyboard' => [
|
||||
[
|
||||
['text' => 'Cliquez ici pour plus d\'infos', 'url' => $url]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
// Convertir le tableau de clavier en JSON
|
||||
$keyboardJson = json_encode($keyboard);
|
||||
|
||||
// Envoyer le message avec les deux boutons
|
||||
Http::get('https://api.telegram.org/bot6784810105:AAEq3emnkRwdyvCLC-iqdIjVJ2Ke6HwwGjg/sendMessage', [
|
||||
'chat_id' => '1970698501',
|
||||
'text' => $text,
|
||||
'reply_markup' => $keyboardJson
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
354
app/Jobs/ProcessTweet.php
Normal file
354
app/Jobs/ProcessTweet.php
Normal file
@@ -0,0 +1,354 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Http\Controllers\APIController;
|
||||
use App\Models\Account;
|
||||
use App\Models\Contest;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
use Illuminate\Support\Arr;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class ProcessTweet implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public $timeout = 90;
|
||||
public $tries = 1;
|
||||
|
||||
private $id;
|
||||
|
||||
private $authid;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct($id,$authid)
|
||||
{
|
||||
$this->id = $id;
|
||||
|
||||
$this->authid= $authid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
|
||||
try{
|
||||
$user = Account::find($this->authid);
|
||||
|
||||
$contest = Contest::findOrFail($this->id);
|
||||
|
||||
$text = $contest->description;
|
||||
|
||||
$tweetspecial = $this->getSpecialComment($text,$user,$contest->tweetid);
|
||||
|
||||
$tweetcomment = $this->getComment($text);
|
||||
|
||||
$tags = $this->getTags($text);
|
||||
|
||||
$hashtags = $this->getHashtags($text);
|
||||
|
||||
$follows = $this->getFollows($text);
|
||||
|
||||
$API = new APIController();
|
||||
|
||||
//On check les notifs
|
||||
$API->unread($user);
|
||||
|
||||
//On Reweet
|
||||
$API->retweet($user, $contest->tweetid);
|
||||
sleep(15);
|
||||
|
||||
|
||||
if (isset($tweetspecial) && isset($tags)) {
|
||||
$retweet = $tweetspecial . ' ' . $tags . ' ' . $hashtags;
|
||||
|
||||
//On reply
|
||||
$API->reply($user, $contest->tweetid, $retweet);
|
||||
sleep(15);
|
||||
|
||||
}elseif(isset($tweetcomment) && isset($tags)) {
|
||||
$comments = config('twitter.sentence_for_tag');
|
||||
$comment = Arr::random($comments);
|
||||
$retweet = $comment . ' ' . $tags . ' ' . $hashtags;
|
||||
|
||||
//On reply
|
||||
$API->reply($user, $contest->tweetid, $retweet);
|
||||
sleep(15);
|
||||
|
||||
|
||||
}elseif(isset($tweetspecial)){
|
||||
$retweet = $tweetspecial . ' ' . $hashtags;
|
||||
|
||||
//On reply
|
||||
$API->reply($user, $contest->tweetid, $retweet);
|
||||
sleep(15);
|
||||
|
||||
|
||||
}elseif(isset($tweetcomment)){
|
||||
$comments = config('twitter.sentence_for_random_comment');
|
||||
$comment = Arr::random($comments);
|
||||
$retweet = $comment . ' ' . $hashtags;
|
||||
|
||||
//On reply
|
||||
$API->reply($user, $contest->tweetid, $retweet);
|
||||
sleep(15);
|
||||
|
||||
|
||||
}elseif(isset($tags)){
|
||||
$retweet = $tags;
|
||||
|
||||
//On reply
|
||||
$API->reply($user, $contest->tweetid, $retweet);
|
||||
sleep(15);
|
||||
|
||||
}
|
||||
|
||||
//On follow le créateur
|
||||
$API->follow($user, $contest->screen);
|
||||
sleep(15);
|
||||
|
||||
|
||||
if(isset($follows)){
|
||||
foreach ($follows as $follow){
|
||||
//On folow les personnes demandées
|
||||
$API->follow($user, $follow);
|
||||
sleep(5);
|
||||
}
|
||||
}
|
||||
|
||||
//On like si besoin
|
||||
preg_match("/LIKE/i", $text, $like);
|
||||
if (isset($like[0])) {
|
||||
//On like le tweet
|
||||
$API->like($user, $contest->tweetid);
|
||||
sleep(15);
|
||||
}
|
||||
|
||||
$nb = rand(3,5);
|
||||
|
||||
if (Cache::has('news')) {
|
||||
$news = Cache::get('news');
|
||||
}else{
|
||||
$news = $API->newstweet($user);
|
||||
}
|
||||
|
||||
shuffle($news);
|
||||
|
||||
$nb = rand(3,5);
|
||||
|
||||
if (count($news) >= $nb) {
|
||||
$selectedArticles = array_slice($news, 0, $nb);
|
||||
|
||||
foreach ($selectedArticles as $article) {
|
||||
$tweetid = $article['conversation_id_str'];
|
||||
$API->retweet($user, $tweetid);
|
||||
sleep(15);
|
||||
}
|
||||
}
|
||||
|
||||
$contest->increment('count');
|
||||
|
||||
return;
|
||||
|
||||
}catch (Exception $exception){
|
||||
$text = "Le compte Twitter " . $user->name . " : " . $exception->getMessage();
|
||||
|
||||
// L'URL des deux liens
|
||||
$url = 'https://myx.ovh/nova/resources/accounts/'.$user->id;
|
||||
|
||||
$keyboard = [
|
||||
'inline_keyboard' => [
|
||||
[
|
||||
['text' => 'Cliquez ici pour plus d\'infos', 'url' => $url]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
// Convertir le tableau de clavier en JSON
|
||||
$keyboardJson = json_encode($keyboard);
|
||||
|
||||
// Envoyer le message avec les deux boutons
|
||||
Http::get('https://api.telegram.org/bot6784810105:AAEq3emnkRwdyvCLC-iqdIjVJ2Ke6HwwGjg/sendMessage', [
|
||||
'chat_id' => '1970698501', // Remplacez par votre chat_id
|
||||
'text' => $text,
|
||||
'reply_markup' => $keyboardJson
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function getSpecialComment($text,$user,$id){
|
||||
|
||||
//On recherche si une reponse special est attendu
|
||||
$word_special_comments = config('twitter.word_special_comment');
|
||||
$combined_regex = implode('|', array_map('preg_quote', $word_special_comments, array_fill(0, count($word_special_comments), '/')));
|
||||
if (preg_match('/' . $combined_regex . '/i', $text, $matches)) {
|
||||
try {
|
||||
$API = new APIController();
|
||||
|
||||
// On check les notifs
|
||||
$texts = $API->getweets($user, $id);
|
||||
|
||||
// Filtrer les phrases vides
|
||||
$texts = array_filter($texts, function($phrase) {
|
||||
return !empty(trim($phrase)); // Ignore les chaînes vides ou contenant uniquement des espaces
|
||||
});
|
||||
|
||||
// Initialiser un tableau pour stocker les occurrences des phrases
|
||||
$occurrences = [];
|
||||
|
||||
foreach ($texts as $index1 => $phrase1) {
|
||||
foreach ($texts as $index2 => $phrase2) {
|
||||
if ($index1 !== $index2) {
|
||||
$similarity = $this->cosineSimilarity($phrase1, $phrase2);
|
||||
// Vous pouvez ajuster le seuil de similarité en fonction de vos besoins
|
||||
if ($similarity > 0.5) {
|
||||
// Incrémenter le compteur pour les deux phrases
|
||||
$occurrences[$index1] = isset($occurrences[$index1]) ? $occurrences[$index1] + 1 : 1;
|
||||
$occurrences[$index2] = isset($occurrences[$index2]) ? $occurrences[$index2] + 1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trouver l'index de la phrase avec le comptage le plus élevé
|
||||
$indexPhrasePlusFrequente = (!empty($occurrences)) ? array_search(max($occurrences), $occurrences) : null;
|
||||
|
||||
// Récupérer la phrase avec le comptage le plus élevé
|
||||
$phrasePlusFrequente = ($indexPhrasePlusFrequente !== null) ? $texts[$indexPhrasePlusFrequente] : null;
|
||||
|
||||
if ($phrasePlusFrequente != null) {
|
||||
// Supprimer les hashtags
|
||||
$phrasePlusFrequente = preg_replace('/#\w+\s?/', '', $phrasePlusFrequente);
|
||||
|
||||
// Supprimer les tags
|
||||
$phrasePlusFrequente = preg_replace('/@\w+\s?/', '', $phrasePlusFrequente);
|
||||
|
||||
// Supprimer les emojis
|
||||
$phrasePlusFrequente = $this->remove_emojis($phrasePlusFrequente);
|
||||
|
||||
return $phrasePlusFrequente;
|
||||
} else {
|
||||
$tweetcomments = config('twitter.sentence_for_random_comment');
|
||||
return Arr::random($tweetcomments);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$tweetcomments = config('twitter.sentence_for_random_comment');
|
||||
return Arr::random($tweetcomments);
|
||||
}
|
||||
}
|
||||
}
|
||||
private function getComment($text){
|
||||
//On recherche si un commentaire est attendu
|
||||
$word_comments = config('twitter.word_comment');
|
||||
$combined_regex = implode('|', array_map('preg_quote', $word_comments, array_fill(0, count($word_comments), '/')));
|
||||
if (preg_match('/' . $combined_regex . '/i', $text, $matches)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
private function getTags($text){
|
||||
//On recherche si ça demande un tag
|
||||
$word_tags = config('twitter.word_tag');
|
||||
$combined_regex = implode('|', array_map('preg_quote', $word_tags, array_fill(0, count($word_tags), '/')));
|
||||
if (preg_match('/' . $combined_regex . '/i', $text, $matches)) {
|
||||
|
||||
//On recherche si ça demande 1 tag
|
||||
$one_people_lists = config('twitter.one_people_list');
|
||||
$combined_regex = implode('|', array_map('preg_quote', $one_people_lists, array_fill(0, count($one_people_lists), '/')));
|
||||
if (preg_match('/' . $combined_regex . '/i', $text, $matches)) {
|
||||
return '@chauchettes';
|
||||
}
|
||||
|
||||
//On recherche si ça demande 2 tags
|
||||
$two_people_lists = config('twitter.two_people_list');
|
||||
$combined_regex = implode('|', array_map('preg_quote', $two_people_lists, array_fill(0, count($two_people_lists), '/')));
|
||||
if (preg_match('/' . $combined_regex . '/i', $text, $matches)) {
|
||||
return '@chauchettes @totorunior';
|
||||
}
|
||||
|
||||
//On recherche si ça demande 3 tags ou plus
|
||||
$three_or_more_people_lists = config('twitter.three_or_more_people_list');
|
||||
$combined_regex = implode('|', array_map('preg_quote', $three_or_more_people_lists, array_fill(0, count($three_or_more_people_lists), '/')));
|
||||
if (preg_match('/' . $combined_regex . '/i', $text, $matches)) {
|
||||
return '@chauchettes @totorunior @crakotte84';
|
||||
}
|
||||
}
|
||||
}
|
||||
private function getHashtags($text){
|
||||
preg_match_all("/#[a-zA-Z0-9]+/", $text, $hashtags);
|
||||
|
||||
if (isset($hashtags[0])) {
|
||||
$hashtags = array_unique($hashtags[0]);
|
||||
$blacklist = config('twitter.hashtag_to_blacklist');
|
||||
|
||||
// Comparer les deux tableaux et supprimer les correspondances du premier tableau
|
||||
$resultLower = array_udiff($hashtags, $blacklist, 'strcasecmp');
|
||||
|
||||
// Construire la chaîne finale des hashtags restants
|
||||
$final = implode(" ", $resultLower);
|
||||
|
||||
return $final;
|
||||
}
|
||||
else{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
private function cosineSimilarity($text1, $text2)
|
||||
{
|
||||
$words1 = str_word_count(strtolower($text1), 1);
|
||||
$words2 = str_word_count(strtolower($text2), 1);
|
||||
|
||||
$allWords = array_unique(array_merge($words1, $words2));
|
||||
$vector1 = $vector2 = [];
|
||||
|
||||
// Construire les vecteurs avec les fréquences des mots
|
||||
foreach ($allWords as $word) {
|
||||
$vector1[] = in_array($word, $words1) ? 1 : 0;
|
||||
$vector2[] = in_array($word, $words2) ? 1 : 0;
|
||||
}
|
||||
|
||||
$dotProduct = 0;
|
||||
|
||||
// Calculer le produit scalaire des vecteurs
|
||||
for ($i = 0; $i < count($allWords); $i++) {
|
||||
$dotProduct += $vector1[$i] * $vector2[$i];
|
||||
}
|
||||
|
||||
$magnitude1 = sqrt(array_sum($vector1));
|
||||
$magnitude2 = sqrt(array_sum($vector2));
|
||||
|
||||
if ($magnitude1 * $magnitude2 == 0) {
|
||||
return 0; // Pour éviter une division par zéro
|
||||
}
|
||||
|
||||
return $dotProduct / ($magnitude1 * $magnitude2);
|
||||
}
|
||||
private function getFollows(mixed $text)
|
||||
{
|
||||
preg_match_all("/\s@([\w_-]+)/", $text, $mentions);
|
||||
|
||||
if(isset($mentions[1])){
|
||||
$mentions = array_unique($mentions[1]);
|
||||
return $mentions;
|
||||
|
||||
}else{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
private function remove_emojis($string)
|
||||
{
|
||||
// Match all emojis (including extended ones)
|
||||
$regex_emojis = '/[\x{1F600}-\x{1F64F}\x{1F300}-\x{1F5FF}\x{1F680}-\x{1F6FF}\x{1F900}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}]/u';
|
||||
$clear_string = preg_replace($regex_emojis, '', $string);
|
||||
|
||||
return $clear_string;
|
||||
}
|
||||
}
|
||||
79
app/Livewire/Contests.php
Normal file
79
app/Livewire/Contests.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\Contest;
|
||||
use App\Models\Account;
|
||||
use App\Jobs\ProcessTweet;
|
||||
use Carbon\Carbon;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
class Contests extends Component
|
||||
{
|
||||
use WithPagination;
|
||||
|
||||
// Fonction appelée lors du chargement du composant
|
||||
public function mount()
|
||||
{
|
||||
// Initial setup if needed
|
||||
}
|
||||
|
||||
// Fonction pour participer automatiquement à un concours
|
||||
public function auto($contestId)
|
||||
{
|
||||
$contest = Contest::find($contestId);
|
||||
|
||||
if (!$contest) {
|
||||
session()->flash('error', 'Concours introuvable.');
|
||||
return;
|
||||
}
|
||||
|
||||
flash()->success('Concours '.$contest->name.' en cours de participation');
|
||||
|
||||
// Récupération des comptes activés
|
||||
$accounts = Account::where('enable', true)->get();
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
ProcessTweet::dispatch($contest->id, $account->id); // Envoi du tweet pour participer
|
||||
}
|
||||
|
||||
// Mise à jour du concours pour indiquer qu'il a été participé
|
||||
$contest->participated = true;
|
||||
$contest->save();
|
||||
|
||||
// Recharger les concours
|
||||
$this->resetPage(); // Reset pagination to the first page
|
||||
}
|
||||
|
||||
// Fonction pour supprimer un concours
|
||||
public function delete($contestId)
|
||||
{
|
||||
$contest = Contest::find($contestId);
|
||||
|
||||
if ($contest) {
|
||||
$contest->enable = false;
|
||||
$contest->save();
|
||||
flash()->error('Concours suppimé');
|
||||
}
|
||||
|
||||
// Recharger les concours après la suppression
|
||||
$this->resetPage(); // Reset pagination to the first page
|
||||
}
|
||||
|
||||
// Fonction pour afficher la vue
|
||||
public function render()
|
||||
{
|
||||
$datefin = Carbon::now()->addDays(3)->format('Y-m-d');
|
||||
$contests = Contest::where('fin', '>=', now())
|
||||
->where('fin', '<=', $datefin)
|
||||
->where('participated', '!=', true)
|
||||
//->where('enable', true)
|
||||
->orderBy('fin', 'asc')
|
||||
->paginate(20);
|
||||
|
||||
return view('livewire.contests', [
|
||||
'contests' => $contests
|
||||
]);
|
||||
}
|
||||
}
|
||||
18
app/Models/Account.php
Normal file
18
app/Models/Account.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Account extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
public $casts = [
|
||||
'password' => 'encrypted',
|
||||
'cookies' => 'encrypted',
|
||||
];
|
||||
|
||||
protected $guarded = ['id'];
|
||||
}
|
||||
13
app/Models/Block.php
Normal file
13
app/Models/Block.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Block extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = ['id'];
|
||||
}
|
||||
18
app/Models/Category.php
Normal file
18
app/Models/Category.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Category extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
public function contests()
|
||||
{
|
||||
return $this->hasMany(Contest::class);
|
||||
}
|
||||
}
|
||||
13
app/Models/Concour.php
Normal file
13
app/Models/Concour.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Concour extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = ['id'];
|
||||
}
|
||||
26
app/Models/Contest.php
Normal file
26
app/Models/Contest.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Contest extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
protected $guarded = [];
|
||||
|
||||
protected $casts = [
|
||||
'fin' => 'date',
|
||||
];
|
||||
|
||||
public function category()
|
||||
{
|
||||
return $this->belongsTo(Category::class);
|
||||
}
|
||||
|
||||
public function organizer()
|
||||
{
|
||||
return $this->belongsTo(Organizer::class);
|
||||
}
|
||||
}
|
||||
13
app/Models/Hashtag.php
Normal file
13
app/Models/Hashtag.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Hashtag extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = ['id'];
|
||||
}
|
||||
18
app/Models/Organizer.php
Normal file
18
app/Models/Organizer.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Organizer extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
public function contests()
|
||||
{
|
||||
return $this->hasMany(Contest::class);
|
||||
}
|
||||
}
|
||||
13
app/Models/Sentence.php
Normal file
13
app/Models/Sentence.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Sentence extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = ['id'];
|
||||
}
|
||||
114
app/Nova/Account.php
Normal file
114
app/Nova/Account.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova;
|
||||
|
||||
use App\Nova\Actions\AutoLogin;
|
||||
use App\Nova\Actions\Connexion;
|
||||
use App\Nova\Actions\Webmail;
|
||||
use App\Nova\Filters\EnableFilter;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Password;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Textarea;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class Account extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Account>
|
||||
*/
|
||||
public static $model = \App\Models\Account::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'id';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
Boolean::make('Enable'),
|
||||
Text::make('Name'),
|
||||
Text::make('Password'),
|
||||
Text::make('Rambler Email')->readonly(),
|
||||
Text::make('Rambler Password')->readonly()->hideFromIndex(),
|
||||
Text::make('Auth Token')->hideFromIndex(),
|
||||
Text::make('Oauth Token')->readonly()->hideFromIndex(),
|
||||
Text::make('Oauth Token Secret')->readonly()->hideFromIndex(),
|
||||
Text::make('Known Device Token')->readonly()->hideFromIndex(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
new EnableFilter(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
Connexion::make(),
|
||||
AutoLogin::make(),
|
||||
Webmail::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
51
app/Nova/Actions/AutoLogin.php
Normal file
51
app/Nova/Actions/AutoLogin.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Actions;
|
||||
|
||||
use foroco\BrowserDetection;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Collection;
|
||||
use Laravel\Nova\Actions\Action;
|
||||
use Laravel\Nova\Fields\ActionFields;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Lexicon\ActionButtonSelector\ActionAsButton;
|
||||
|
||||
class AutoLogin extends Action
|
||||
{
|
||||
use InteractsWithQueue, Queueable;
|
||||
use ActionAsButton;
|
||||
|
||||
/**
|
||||
* Perform the action on the given models.
|
||||
*
|
||||
* @param \Laravel\Nova\Fields\ActionFields $fields
|
||||
* @param \Illuminate\Support\Collection $models
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(ActionFields $fields, Collection $models)
|
||||
{
|
||||
$Browser = new BrowserDetection();
|
||||
$useragent = $_SERVER['HTTP_USER_AGENT'];
|
||||
|
||||
if (str_contains($Browser->getOS($useragent)['os_family'], 'android')) {
|
||||
// Générer un lien spécifique pour Kiwi
|
||||
$kiwiLink = 'intent://x.com?auth_token='.$models->first()->auth_token.'#Intent;package=com.kiwibrowser.browser;scheme=https;end';
|
||||
return Action::redirect($kiwiLink);
|
||||
}
|
||||
|
||||
return Action::openInNewTab('https://x.com?auth_token='.$models->first()->auth_token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields available on the action.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
54
app/Nova/Actions/Connexion.php
Normal file
54
app/Nova/Actions/Connexion.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Actions;
|
||||
|
||||
use App\Http\Controllers\AccountController;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Collection;
|
||||
use Laravel\Nova\Actions\Action;
|
||||
use Laravel\Nova\Fields\ActionFields;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Lexicon\ActionButtonSelector\ActionAsButton;
|
||||
use App\Http\Controllers\TwitterController;
|
||||
|
||||
class Connexion extends Action
|
||||
{
|
||||
use InteractsWithQueue, Queueable;
|
||||
use ActionAsButton;
|
||||
|
||||
/**
|
||||
* Perform the action on the given models.
|
||||
*
|
||||
* @param \Laravel\Nova\Fields\ActionFields $fields
|
||||
* @param \Illuminate\Support\Collection $models
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(ActionFields $fields, Collection $models)
|
||||
{
|
||||
//return Action::openInNewTab('/login/'.$models->first()->id);
|
||||
|
||||
$connexion = (new AccountController)->login($models->first()->id);
|
||||
|
||||
if($connexion){
|
||||
return Action::message('Compte synchronisé');
|
||||
}elseif(!$connexion){
|
||||
return Action::message('Erreur de connexion');
|
||||
}else{
|
||||
return $connexion;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields available on the action.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
57
app/Nova/Actions/Participer.php
Normal file
57
app/Nova/Actions/Participer.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Actions;
|
||||
|
||||
use App\Models\Contest;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Collection;
|
||||
use Laravel\Nova\Actions\Action;
|
||||
use Laravel\Nova\Fields\ActionFields;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Lexicon\ActionButtonSelector\ActionAsButton;
|
||||
use App\Http\Controllers\TwitterController;
|
||||
|
||||
class Participer extends Action
|
||||
{
|
||||
use InteractsWithQueue, Queueable;
|
||||
use ActionAsButton;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->withoutConfirmation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the action on the given models.
|
||||
*
|
||||
* @param \Laravel\Nova\Fields\ActionFields $fields
|
||||
* @param \Illuminate\Support\Collection $models
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(ActionFields $fields, Collection $models)
|
||||
{
|
||||
if($models->first()->participated == 1){
|
||||
Action::danger('Vous avez déjà participé');
|
||||
}
|
||||
else{
|
||||
$contest = Contest::find($models->first()->id);
|
||||
$contest->participated = 1;
|
||||
$contest->save();
|
||||
Action::message('Participation en cours');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields available on the action.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
44
app/Nova/Actions/Webmail.php
Normal file
44
app/Nova/Actions/Webmail.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Actions;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Collection;
|
||||
use Laravel\Nova\Actions\Action;
|
||||
use Laravel\Nova\Fields\ActionFields;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Lexicon\ActionButtonSelector\ActionAsButton;
|
||||
|
||||
class Webmail extends Action
|
||||
{
|
||||
use InteractsWithQueue, Queueable;
|
||||
use ActionAsButton;
|
||||
|
||||
/**
|
||||
* Perform the action on the given models.
|
||||
*
|
||||
* @param \Laravel\Nova\Fields\ActionFields $fields
|
||||
* @param \Illuminate\Support\Collection $models
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(ActionFields $fields, Collection $models)
|
||||
{
|
||||
$mail = urlencode($models->first()->rambler_email);
|
||||
$password = urlencode($models->first()->rambler_password);
|
||||
|
||||
return Action::openInNewTab('https://mail.myx.ovh/?postlogin&Email='.$mail.'&Password='.$password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields available on the action.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
92
app/Nova/Block.php
Normal file
92
app/Nova/Block.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class Block extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Block>
|
||||
*/
|
||||
public static $model = \App\Models\Block::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'screen_name';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'screen_name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
Text::make('screen_name'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
121
app/Nova/Contest.php
Normal file
121
app/Nova/Contest.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova;
|
||||
|
||||
use App\Nova\Actions\Participer;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\Date;
|
||||
use Laravel\Nova\Fields\DateTime;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Image;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Textarea;
|
||||
use Laravel\Nova\Fields\URL;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class Contest extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Contest>
|
||||
*/
|
||||
public static $model = \App\Models\Contest::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'name',
|
||||
];
|
||||
|
||||
public static function indexQuery(NovaRequest $request, $query): \Illuminate\Database\Eloquent\Builder
|
||||
{
|
||||
return $query->where('fin', '>=', now())->where('participated', '!=', true);
|
||||
}
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
Boolean::make('Participate', 'participated'),
|
||||
Text::make('Name')->readonly(),
|
||||
Text::make('Screen')->readonly(),
|
||||
Text::make('Description')->readonly(),
|
||||
Text::make('Nb Like', 'nblike')->readonly(),
|
||||
Text::make('Nb Reply', 'nbreply')->readonly(),
|
||||
Image::make('Image', 'picture')
|
||||
->thumbnail(function ($value) {
|
||||
return $value;
|
||||
})
|
||||
->preview(function ($value) {
|
||||
return $value;
|
||||
})
|
||||
->disableDownload(),
|
||||
URL::make('URL')->readonly(),
|
||||
Date::make('Fin')->readonly()->sortable(),
|
||||
Text::make('Tweet ID', 'tweetid')->hideFromIndex()->readonly(),
|
||||
Text::make('Nb Tweet', 'nbtweet')->readonly(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
Participer::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
21
app/Nova/Dashboards/Main.php
Normal file
21
app/Nova/Dashboards/Main.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Dashboards;
|
||||
|
||||
use Laravel\Nova\Cards\Help;
|
||||
use Laravel\Nova\Dashboards\Main as Dashboard;
|
||||
|
||||
class Main extends Dashboard
|
||||
{
|
||||
/**
|
||||
* Get the cards for the dashboard.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards()
|
||||
{
|
||||
return [
|
||||
new Help,
|
||||
];
|
||||
}
|
||||
}
|
||||
38
app/Nova/Filters/EnableFilter.php
Normal file
38
app/Nova/Filters/EnableFilter.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Filters;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Filters\Boolean;
|
||||
use Laravel\Nova\Filters\Filter;
|
||||
|
||||
class EnableFilter extends Filter
|
||||
{
|
||||
public $name = 'Enabled Filter';
|
||||
|
||||
/**
|
||||
* Apply the filter to the given resource query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param string $value
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function apply(Request $request, $query, $value)
|
||||
{
|
||||
return $query->where('enable', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter's available options.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function options(Request $request)
|
||||
{
|
||||
return [
|
||||
'Enabled' => 1,
|
||||
'Disabled' => 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
92
app/Nova/Hashtag.php
Normal file
92
app/Nova/Hashtag.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class Hashtag extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Hashtag>
|
||||
*/
|
||||
public static $model = \App\Models\Hashtag::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
Text::make('Name'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
62
app/Nova/Metrics/ConcoursPerDay.php
Normal file
62
app/Nova/Metrics/ConcoursPerDay.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Metrics;
|
||||
|
||||
use App\Models\Concour;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Laravel\Nova\Metrics\Trend;
|
||||
|
||||
class ConcoursPerDay extends Trend
|
||||
{
|
||||
/**
|
||||
* Calculate the value of the metric.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function calculate(NovaRequest $request)
|
||||
{
|
||||
return $this->countByDays($request, Concour::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ranges available for the metric.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function ranges()
|
||||
{
|
||||
return [
|
||||
7 => __('7 Jours'),
|
||||
14 => __('14 Jours'),
|
||||
30 => __('30 Jours'),
|
||||
60 => __('60 Jours'),
|
||||
90 => __('90 Jours'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the amount of time the results of the metric should be cached.
|
||||
*
|
||||
* @return \DateTimeInterface|\DateInterval|float|int|null
|
||||
*/
|
||||
public function cacheFor()
|
||||
{
|
||||
// return now()->addMinutes(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URI key for the metric.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function uriKey()
|
||||
{
|
||||
return 'concours-per-day';
|
||||
}
|
||||
|
||||
public function name()
|
||||
{
|
||||
return 'Tendances des Concours';
|
||||
}
|
||||
}
|
||||
54
app/Nova/Metrics/NewConcours.php
Normal file
54
app/Nova/Metrics/NewConcours.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Metrics;
|
||||
|
||||
use App\Models\Concour;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Laravel\Nova\Metrics\Value;
|
||||
|
||||
class NewConcours extends Value
|
||||
{
|
||||
/**
|
||||
* Calculate the value of the metric.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function calculate(NovaRequest $request)
|
||||
{
|
||||
return $this->count($request, Concour::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ranges available for the metric.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function ranges()
|
||||
{
|
||||
return [
|
||||
'TODAY' => __('Aujourd\'hui'),
|
||||
30 => __('30 Jours'),
|
||||
60 => __('60 Jours'),
|
||||
365 => __('365 Jours'),
|
||||
'MTD' => __('Mois à date'),
|
||||
'QTD' => __('Trimestre à date'),
|
||||
'YTD' => __('Année à date'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the amount of time the results of the metric should be cached.
|
||||
*
|
||||
* @return \DateTimeInterface|\DateInterval|float|int|null
|
||||
*/
|
||||
public function cacheFor()
|
||||
{
|
||||
// return now()->addMinutes(5);
|
||||
}
|
||||
|
||||
public function name()
|
||||
{
|
||||
return 'Concours Participés';
|
||||
}
|
||||
}
|
||||
46
app/Nova/Metrics/UserPerConcours.php
Normal file
46
app/Nova/Metrics/UserPerConcours.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Metrics;
|
||||
|
||||
use App\Models\Concour;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Laravel\Nova\Metrics\Partition;
|
||||
|
||||
class UserPerConcours extends Partition
|
||||
{
|
||||
/**
|
||||
* Calculate the value of the metric.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function calculate(NovaRequest $request)
|
||||
{
|
||||
return $this->count($request, Concour::class, 'description');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the amount of time the results of the metric should be cached.
|
||||
*
|
||||
* @return \DateTimeInterface|\DateInterval|float|int|null
|
||||
*/
|
||||
public function cacheFor()
|
||||
{
|
||||
// return now()->addMinutes(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URI key for the metric.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function uriKey()
|
||||
{
|
||||
return 'user-per-concours';
|
||||
}
|
||||
|
||||
public function name()
|
||||
{
|
||||
return 'Organisateurs';
|
||||
}
|
||||
}
|
||||
59
app/Nova/Resource.php
Normal file
59
app/Nova/Resource.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova;
|
||||
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Laravel\Nova\Resource as NovaResource;
|
||||
|
||||
abstract class Resource extends NovaResource
|
||||
{
|
||||
/**
|
||||
* Build an "index" query for the given resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public static function indexQuery(NovaRequest $request, $query)
|
||||
{
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Scout search query for the given resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @param \Laravel\Scout\Builder $query
|
||||
* @return \Laravel\Scout\Builder
|
||||
*/
|
||||
public static function scoutQuery(NovaRequest $request, $query)
|
||||
{
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a "detail" query for the given resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public static function detailQuery(NovaRequest $request, $query)
|
||||
{
|
||||
return parent::detailQuery($request, $query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a "relatable" query for the given resource.
|
||||
*
|
||||
* This query determines which instances of the model may be attached to other resources.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public static function relatableQuery(NovaRequest $request, $query)
|
||||
{
|
||||
return parent::relatableQuery($request, $query);
|
||||
}
|
||||
}
|
||||
92
app/Nova/Sentence.php
Normal file
92
app/Nova/Sentence.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class Sentence extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Sentence>
|
||||
*/
|
||||
public static $model = \App\Models\Sentence::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
Text::make('Name'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
111
app/Nova/User.php
Normal file
111
app/Nova/User.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rules;
|
||||
use Laravel\Nova\Fields\Gravatar;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Password;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class User extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\User>
|
||||
*/
|
||||
public static $model = \App\Models\User::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'name', 'email',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Gravatar::make()->maxWidth(50),
|
||||
|
||||
Text::make('Name')
|
||||
->sortable()
|
||||
->rules('required', 'max:255'),
|
||||
|
||||
Text::make('Email')
|
||||
->sortable()
|
||||
->rules('required', 'email', 'max:254')
|
||||
->creationRules('unique:users,email')
|
||||
->updateRules('unique:users,email,{{resourceId}}'),
|
||||
|
||||
Password::make('Password')
|
||||
->onlyOnForms()
|
||||
->creationRules('required', Rules\Password::defaults())
|
||||
->updateRules('nullable', Rules\Password::defaults()),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
81
app/Providers/NovaServiceProvider.php
Normal file
81
app/Providers/NovaServiceProvider.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Laravel\Nova\Nova;
|
||||
use Laravel\Nova\NovaApplicationServiceProvider;
|
||||
|
||||
class NovaServiceProvider extends NovaApplicationServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
parent::boot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the Nova routes.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function routes()
|
||||
{
|
||||
Nova::routes()
|
||||
->withAuthenticationRoutes()
|
||||
->withPasswordResetRoutes()
|
||||
->register();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the Nova gate.
|
||||
*
|
||||
* This gate determines who can access Nova in non-local environments.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function gate()
|
||||
{
|
||||
Gate::define('viewNova', function ($user) {
|
||||
return in_array($user->email, [
|
||||
'hugo.lafay@gmail.com'
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dashboards that should be listed in the Nova sidebar.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function dashboards()
|
||||
{
|
||||
return [
|
||||
new \App\Nova\Dashboards\Main,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tools that should be listed in the Nova sidebar.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function tools()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user