|
70981
|
2550
|
9
|
2026-05-22T11:01:49.428810+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447709428_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpAPP (DOCKERDEV SlackFileEditViewGoHistoryWindowHelpAPP (DOCKERDEV (-zsh)O $82APP (-zsh)tests/Unit/Services/Activity/RingCentral/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/TwilioVideoMetadataHandlerTest.phptests/Unit/Services/Kiosk/AutomatedReports/AutomatedReportsServiceTest.phptests/Unit/Services/Mail/0ffice/EmailApiClientTest.phptests/Unit/Services/Mail/TextRelayServiceTest.phptests/Unit/Services/RecallAI/RecallAIServiceTest.php79 files changed, 4254 insertions(+), 2020 deletions(-)create mode 100644 .github/claude-reviewer/no-ticket-warning.txtcreate mode 100644 .github/claude-reviewer/scripts/fetch-jira-context.mjsdelete mode 100644 app/Component/ES/Processor/BatchStatusInterface.phpcreatemode 100644 app/Component/ES/Processor/RedisEntityExtractor.phpdelete mode100644 app/Component/ES/Processor/Traits/WorkerIdTrait.phpcreate mode 100644 app/Component/ES/QueuePriorityEnum.phpTrginusWorker/aTrai+: Phpcreate mode 100644 front-end/src/components/DealInsights/Modals/__tests__/AskAnythingModacreate mode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Asdeletemode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Ascreatemode 100644 tests/Unit/Component/ES/Processor/RedisEntityExtractorTest.phpdelete mode 100644 tests/Unit/Component/ES/Processor/Traits/WorkerIdTraitTest.phpcreate mode 100644 tests/Unit/Component/ES/QueuePriorityEnumTest.phpcreate mode 100644 tests/Unit/Notifications/Activities/SmsReceivedTest.phpcreate mode 100644 tests/Unit/Services/Mail/TextRelayServiceTest.phplukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20963-fix-imporSwitched to a new branch 'JY-20963-fix-import-on-deleted-entity'lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20963-fix-import-on-deleted-entdocker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn moreat [URL_WITH_CREDENTIALS] (JY-20963-fix-import-on-deleted-ent|docker exec -it docker_lamp_1./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.PHPruntime: 8.3.30Running analysis on 7 cores with 10 files perprocess.Parallel runner is an experimental feature and may be unstable, use itat your ownrisk.Loaded config default from".php-cs-fixer.dist.php"5691/5691100%Fixed 0 of 5691 files in 96.077 seconds, 67.00 MBmemory used•HomeDMsActivityFilesLater+ED→Jiminny ...& jiminny-x-integrati...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# happy_birthday# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messagesP. Galya Dimitrova ". Nikolay YankovP. Aneliya Angelova. Stoyan Tanev& James Graham> 0(all100% С8 • Fri 22 May 14:01:48Describe what you are looking for# releases8 226 0• MessagesProject: appC FilesBookmarksM/kan.Today ~J26+10:26:05Tag:View JobGitHub APP1:27 PM4 new commits pushed tomaster byTodorStamatovJiminnycbf9b72b - JY-20955: fix calendar eventduplication checkafe8dceg - Merge branch 'master' into JY-20955-multiple-calendars-events218a8602 - Merge branch 'master' into JY-20955-multiple-calendars-eventsbe560cbf - Merge pull request #12119 fromjiminny/JY-20955-multiple-calendars-eventsjiminny/app | Added by GitHubNewCircleCl APP 1:53 PMDeployment Successful!Project: appWhen:05/22/202610:53:15Tag:View JobMessage #releases+Aa..•...
|
NULL
|
-1091239442481050444
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpAPP (DOCKERDEV SlackFileEditViewGoHistoryWindowHelpAPP (DOCKERDEV (-zsh)O $82APP (-zsh)tests/Unit/Services/Activity/RingCentral/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/TwilioVideoMetadataHandlerTest.phptests/Unit/Services/Kiosk/AutomatedReports/AutomatedReportsServiceTest.phptests/Unit/Services/Mail/0ffice/EmailApiClientTest.phptests/Unit/Services/Mail/TextRelayServiceTest.phptests/Unit/Services/RecallAI/RecallAIServiceTest.php79 files changed, 4254 insertions(+), 2020 deletions(-)create mode 100644 .github/claude-reviewer/no-ticket-warning.txtcreate mode 100644 .github/claude-reviewer/scripts/fetch-jira-context.mjsdelete mode 100644 app/Component/ES/Processor/BatchStatusInterface.phpcreatemode 100644 app/Component/ES/Processor/RedisEntityExtractor.phpdelete mode100644 app/Component/ES/Processor/Traits/WorkerIdTrait.phpcreate mode 100644 app/Component/ES/QueuePriorityEnum.phpTrginusWorker/aTrai+: Phpcreate mode 100644 front-end/src/components/DealInsights/Modals/__tests__/AskAnythingModacreate mode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Asdeletemode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Ascreatemode 100644 tests/Unit/Component/ES/Processor/RedisEntityExtractorTest.phpdelete mode 100644 tests/Unit/Component/ES/Processor/Traits/WorkerIdTraitTest.phpcreate mode 100644 tests/Unit/Component/ES/QueuePriorityEnumTest.phpcreate mode 100644 tests/Unit/Notifications/Activities/SmsReceivedTest.phpcreate mode 100644 tests/Unit/Services/Mail/TextRelayServiceTest.phplukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20963-fix-imporSwitched to a new branch 'JY-20963-fix-import-on-deleted-entity'lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20963-fix-import-on-deleted-entdocker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn moreat [URL_WITH_CREDENTIALS] (JY-20963-fix-import-on-deleted-ent|docker exec -it docker_lamp_1./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.PHPruntime: 8.3.30Running analysis on 7 cores with 10 files perprocess.Parallel runner is an experimental feature and may be unstable, use itat your ownrisk.Loaded config default from".php-cs-fixer.dist.php"5691/5691100%Fixed 0 of 5691 files in 96.077 seconds, 67.00 MBmemory used•HomeDMsActivityFilesLater+ED→Jiminny ...& jiminny-x-integrati...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# happy_birthday# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messagesP. Galya Dimitrova ". Nikolay YankovP. Aneliya Angelova. Stoyan Tanev& James Graham> 0(all100% С8 • Fri 22 May 14:01:48Describe what you are looking for# releases8 226 0• MessagesProject: appC FilesBookmarksM/kan.Today ~J26+10:26:05Tag:View JobGitHub APP1:27 PM4 new commits pushed tomaster byTodorStamatovJiminnycbf9b72b - JY-20955: fix calendar eventduplication checkafe8dceg - Merge branch 'master' into JY-20955-multiple-calendars-events218a8602 - Merge branch 'master' into JY-20955-multiple-calendars-eventsbe560cbf - Merge pull request #12119 fromjiminny/JY-20955-multiple-calendars-eventsjiminny/app | Added by GitHubNewCircleCl APP 1:53 PMDeployment Successful!Project: appWhen:05/22/202610:53:15Tag:View JobMessage #releases+Aa..•...
|
70979
|
NULL
|
NULL
|
NULL
|
|
70982
|
2551
|
14
|
2026-05-22T11:01:52.586521+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447712586_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormFV faVsco.js°9 master kroledey© InsightsSe PhostormFV faVsco.js°9 master kroledey© InsightsService.php© NumberAllocator.php1extmessagingservice.onpc I willoclient.onpcIwlloclientbullder.pnpcIwilloservice.ono•D UserPilot_ WebhookC AbstractService.php© ActivitvProviderFactory.php©) [EMAIL]© ConferenceService.phpC)InsiahtSeatService.oho© InstantMeetingService.php© IntercomService.php© IpapiClient.php(c) Inan Service nhn© ParticipantShareService.php@ PlanhatService.php© PlaybackService.phpPlaybackVideoOnlyService.php© PlaybookCategoryService.php© PlaylistGeneratorinterface.phpkesolveleamermeonnection.ong© SimpleThrottleService.php@ ClackService.php© SocialAccountService.php© SoftPhoneService.php© TeamDeactivatedService.php© TeamOwnerService.php123 19)c) Teamservice.php© TranscodeParameterResolver.phpc Userservice.onrLocal changesShelfConsole xLog Xenv.local aon@.liminnvDehuaCommandinhn ann/ConcolelCommandepho loadina nhn confialg SoftPhoneManager.php app/Component/Twilio/Conference/ConferenceManag© TextMessagingService.php app/Services/TelephonyUnversioned Files 9 filesE.env.nikilocal appE.env.other app© CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/R6 favicon.ico publicEids.txt aprTraw saL querv.sal appC) SimulateWebhooksCommand.oho app/Console/Commands/Crm/HubspotM+ WEBHOOK FILTERING IMPLEMENTATION.md appsynerorlannatpnp©PlaybackController.phppnp api.phpC) CreateSmsSentEvent.php(C) PlanhatActivityListener.pho(C)AskAnythingPromptService.php© AutomatedReportsRepository.php(C) AutomatedReportsCommand.phpphp api v2.phpC) RequestGenerateReportJob.pho(C) AutomatedReportResult.php© AutomatedReport.phpclass UserAutomatedReportsController extends ControllerBI4NLAY70 (61pubulc tunccion -_conscruceprivate readonly AutomatedReportsRepository $automatedReportsRepositoryprivace readonly Aucomareckeporcsservice saucomareakeportsservice.private readonly Apikesponseservice sapikesponseservice,private readonly kesponse sresponse.private readonly PlanhatService $planhatService,{...1PosTlaoi/vilautomated-reports/interest 1 usagepublic function trackInterest(Request Srequest): JsonResponsef...?* othrows ApplicationExceotionG-Taoi/vlautomated-renortsnublic function List(Request Srequest): IsonResnonsef.}DELETE lanilv1/automated-renorts/uuidpublic function delete(Request Srequest, string $uuid): JsonResponsel...}+ → @ Side-by-side viewer ~Do not ianore vHighlight words 13 g ?81aee7aadScontact = nulliCctane = null.Sopportunity = null;/ Setup services.ScrmService = $this->crmProviderRegistry->get(Steam->crm->provider):if (! Suser->isCrmRequiredo){ScrmService->setUser(Suser->team->owner):} else {scrmservice->serusersusercustom.log= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]© TextMessagingService.php X A console [EU]A console [STAGING]stohenamespace Jininny services lelephony>use ...class TextMessaqngServiceorivate ?Team steam = nulu3 usadesorivate ?TwilioClient Stwilionlient = nultpublic function __construct(private readonly ProviderRegistry $providerRegistry,private readonly ActivityService SactivityService,private readonly Webhook SurlGeneratorprivate readonly TwilioClientBuilder $twilioClientBuilder,* Othrows ConfigurationExceptionpublic function setTeam(Team $team): voidsth1s->team = steam:Sthis-›twilioClient = Sthis->twilioClientBuilder->build(Steam):* Athrows \ExceptionPsvewi all nlaces in the code where we could uceoublic function sendUser Sfrom. strina Sto. strina Smessage): Messagelnstancelcurrent versionScontact = null;$stage = null;Sopportunity = null;try {ScrmResolver = app(Crm0wnerResolver::class,'team' => $team'integrationAdmin' => $usen'providerSlug' => $team->getCrmConfiqurationO->qetProviderNameOScrmService = ScrmResolver->prepareCrmService0:} catch (\Throwable Sthrowable){100% 2• Fri 22 May 14:01:52U AskJiminnyReportActivityServiceTest vCascadeInvestigate Foreign KeSalestorce Token Fallb+0 ..122 V1 V1 AVThe file is still off lot of warning just see what is wrongThoughtsInought tor 1sI see the issue - the try-catch structure is broken. The catch block on line 147 for SocialAccountTokenInvalidExceptionhas no matching try block because the CRM usage code (lines 115-146) is not wrapped in a try block.• TextMessagingService.phrnckcalonFixed the trv-catch olock structure in TextMessagingService, The issue was that the catch olock tor Social AccountTokeninvalidException (line 147) had no matching try block - the CRM usage code wasn't wrapped in a try block after I added the1. SoftPhoneManager.php - Added CrmOwnerResolver fallback for both outbound and inbound Twilio calls2. TextMessagingService.php - Added CrmOwnerResolver fallback for both buildActivity and convertCustomerToCouncrylode metnoas, with proper try-catch structureBoth imolementations now:• First try CrmOwnerResolver to find an active Salesforce token from the organization• If that fails, fall back to the original direct user assignment pattern• Let existing outer catch blocks handle any Socia AccountTokenInvalidException by settina CRM data to nullThis ensures Twilio calls will use another active Salesforce token when the admin token expires, preventing "Unknownl .2 differencasW Windsurf Teamc1-1.UTE.8Po 4 spaces...
|
NULL
|
4788349043390683887
|
NULL
|
click
|
ocr
|
NULL
|
PhostormFV faVsco.js°9 master kroledey© InsightsSe PhostormFV faVsco.js°9 master kroledey© InsightsService.php© NumberAllocator.php1extmessagingservice.onpc I willoclient.onpcIwlloclientbullder.pnpcIwilloservice.ono•D UserPilot_ WebhookC AbstractService.php© ActivitvProviderFactory.php©) [EMAIL]© ConferenceService.phpC)InsiahtSeatService.oho© InstantMeetingService.php© IntercomService.php© IpapiClient.php(c) Inan Service nhn© ParticipantShareService.php@ PlanhatService.php© PlaybackService.phpPlaybackVideoOnlyService.php© PlaybookCategoryService.php© PlaylistGeneratorinterface.phpkesolveleamermeonnection.ong© SimpleThrottleService.php@ ClackService.php© SocialAccountService.php© SoftPhoneService.php© TeamDeactivatedService.php© TeamOwnerService.php123 19)c) Teamservice.php© TranscodeParameterResolver.phpc Userservice.onrLocal changesShelfConsole xLog Xenv.local aon@.liminnvDehuaCommandinhn ann/ConcolelCommandepho loadina nhn confialg SoftPhoneManager.php app/Component/Twilio/Conference/ConferenceManag© TextMessagingService.php app/Services/TelephonyUnversioned Files 9 filesE.env.nikilocal appE.env.other app© CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/R6 favicon.ico publicEids.txt aprTraw saL querv.sal appC) SimulateWebhooksCommand.oho app/Console/Commands/Crm/HubspotM+ WEBHOOK FILTERING IMPLEMENTATION.md appsynerorlannatpnp©PlaybackController.phppnp api.phpC) CreateSmsSentEvent.php(C) PlanhatActivityListener.pho(C)AskAnythingPromptService.php© AutomatedReportsRepository.php(C) AutomatedReportsCommand.phpphp api v2.phpC) RequestGenerateReportJob.pho(C) AutomatedReportResult.php© AutomatedReport.phpclass UserAutomatedReportsController extends ControllerBI4NLAY70 (61pubulc tunccion -_conscruceprivate readonly AutomatedReportsRepository $automatedReportsRepositoryprivace readonly Aucomareckeporcsservice saucomareakeportsservice.private readonly Apikesponseservice sapikesponseservice,private readonly kesponse sresponse.private readonly PlanhatService $planhatService,{...1PosTlaoi/vilautomated-reports/interest 1 usagepublic function trackInterest(Request Srequest): JsonResponsef...?* othrows ApplicationExceotionG-Taoi/vlautomated-renortsnublic function List(Request Srequest): IsonResnonsef.}DELETE lanilv1/automated-renorts/uuidpublic function delete(Request Srequest, string $uuid): JsonResponsel...}+ → @ Side-by-side viewer ~Do not ianore vHighlight words 13 g ?81aee7aadScontact = nulliCctane = null.Sopportunity = null;/ Setup services.ScrmService = $this->crmProviderRegistry->get(Steam->crm->provider):if (! Suser->isCrmRequiredo){ScrmService->setUser(Suser->team->owner):} else {scrmservice->serusersusercustom.log= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]© TextMessagingService.php X A console [EU]A console [STAGING]stohenamespace Jininny services lelephony>use ...class TextMessaqngServiceorivate ?Team steam = nulu3 usadesorivate ?TwilioClient Stwilionlient = nultpublic function __construct(private readonly ProviderRegistry $providerRegistry,private readonly ActivityService SactivityService,private readonly Webhook SurlGeneratorprivate readonly TwilioClientBuilder $twilioClientBuilder,* Othrows ConfigurationExceptionpublic function setTeam(Team $team): voidsth1s->team = steam:Sthis-›twilioClient = Sthis->twilioClientBuilder->build(Steam):* Athrows \ExceptionPsvewi all nlaces in the code where we could uceoublic function sendUser Sfrom. strina Sto. strina Smessage): Messagelnstancelcurrent versionScontact = null;$stage = null;Sopportunity = null;try {ScrmResolver = app(Crm0wnerResolver::class,'team' => $team'integrationAdmin' => $usen'providerSlug' => $team->getCrmConfiqurationO->qetProviderNameOScrmService = ScrmResolver->prepareCrmService0:} catch (\Throwable Sthrowable){100% 2• Fri 22 May 14:01:52U AskJiminnyReportActivityServiceTest vCascadeInvestigate Foreign KeSalestorce Token Fallb+0 ..122 V1 V1 AVThe file is still off lot of warning just see what is wrongThoughtsInought tor 1sI see the issue - the try-catch structure is broken. The catch block on line 147 for SocialAccountTokenInvalidExceptionhas no matching try block because the CRM usage code (lines 115-146) is not wrapped in a try block.• TextMessagingService.phrnckcalonFixed the trv-catch olock structure in TextMessagingService, The issue was that the catch olock tor Social AccountTokeninvalidException (line 147) had no matching try block - the CRM usage code wasn't wrapped in a try block after I added the1. SoftPhoneManager.php - Added CrmOwnerResolver fallback for both outbound and inbound Twilio calls2. TextMessagingService.php - Added CrmOwnerResolver fallback for both buildActivity and convertCustomerToCouncrylode metnoas, with proper try-catch structureBoth imolementations now:• First try CrmOwnerResolver to find an active Salesforce token from the organization• If that fails, fall back to the original direct user assignment pattern• Let existing outer catch blocks handle any Socia AccountTokenInvalidException by settina CRM data to nullThis ensures Twilio calls will use another active Salesforce token when the admin token expires, preventing "Unknownl .2 differencasW Windsurf Teamc1-1.UTE.8Po 4 spaces...
|
70980
|
NULL
|
NULL
|
NULL
|
|
70983
|
2551
|
15
|
2026-05-22T11:01:56.535071+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447716535_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"bounds":{"left":0.390625,"top":0.2490024,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.40226063,"top":0.2490024,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.4119016,"top":0.24740623,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.4192154,"top":0.24740623,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"bounds":{"left":0.6911569,"top":0.10055866,"width":0.009973404,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.703125,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.7124335,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.72140956,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7287234,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","depth":4,"bounds":{"left":0.4481383,"top":0.09736632,"width":0.36269948,"height":0.90263367},"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8419801864614017883
|
-4357855742655358964
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
70985
|
2550
|
11
|
2026-05-22T11:01:58.698652+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447718698_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5111928977143741995
|
-3204935344002590708
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
70984
|
NULL
|
NULL
|
NULL
|
|
70986
|
2551
|
16
|
2026-05-22T11:01:58.585670+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447718585_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"bounds":{"left":0.390625,"top":0.2490024,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.40226063,"top":0.2490024,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.4119016,"top":0.24740623,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.4192154,"top":0.24740623,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"bounds":{"left":0.6911569,"top":0.10055866,"width":0.009973404,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.703125,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.7124335,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.72140956,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7287234,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","depth":4,"bounds":{"left":0.4481383,"top":0.09736632,"width":0.36269948,"height":0.90263367},"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5111928977143741995
|
-3204935344002590708
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
70983
|
NULL
|
NULL
|
NULL
|
|
70987
|
2550
|
12
|
2026-05-22T11:02:04.966457+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447724966_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"on_screen":true,"role_description":"text"}]...
|
-8982858087525314945
|
-3916720581518444019
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
70988
|
2550
|
13
|
2026-05-22T11:02:11.346978+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447731346_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5111928977143741995
|
-3204935344002590708
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
70987
|
NULL
|
NULL
|
NULL
|
|
70989
|
2550
|
14
|
2026-05-22T11:02:41.747311+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447761747_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5111928977143741995
|
-3204935344002590708
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
70990
|
2551
|
17
|
2026-05-22T11:02:41.797481+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447761797_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"bounds":{"left":0.390625,"top":0.2490024,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.40226063,"top":0.2490024,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.4119016,"top":0.24740623,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.4192154,"top":0.24740623,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"bounds":{"left":0.6911569,"top":0.10055866,"width":0.009973404,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.703125,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.7124335,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.72140956,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7287234,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","depth":4,"bounds":{"left":0.4481383,"top":0.09736632,"width":0.36269948,"height":0.90263367},"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5111928977143741995
|
-3204935344002590708
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
70991
|
2550
|
15
|
2026-05-22T11:03:00.009039+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447780009_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2756535304298618912
|
-2619120939016537587
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}...
|
70989
|
NULL
|
NULL
|
NULL
|
|
70992
|
2551
|
18
|
2026-05-22T11:02:59.846013+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447779846_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"bounds":{"left":0.390625,"top":0.2490024,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.40226063,"top":0.2490024,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.4119016,"top":0.24740623,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.4192154,"top":0.24740623,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7460324410827463904
|
-8204420481061508160
|
typing_pause
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
PhostormFV faVsco.js°9 master kroledey© InsightsService.php© NumberAllocator.php1extmessagingservice.pngc I willoclient.onpcIwlloclientbullder.pnpcIwilloservice.ono•D UserPilot_ WebhookC AbstractService.php© ActivitvProviderFactory.php©) [EMAIL]© ConferenceService.phpC)InsiahtSeatService.oho© InstantMeetingService.php© IntercomService.php© IpapiClient.php(c) Inan Service nhnl© ParticipantShareService.php@ PlanhatService.php© PlaybackService.phpPlaybackVideoOnlyService.php© PlaybookCategoryService.php© PlaylistGeneratorinterface.phpkesolveleamermeonnection.ong© SimpleThrottleService.php@ ClackService.php© SocialAccountService.php© SoftPhoneService.php© TeamDeactivatedService.php© TeamOwnerService.php123 19)c) Teamservice.php© TranscodeParameterResolver.phpc Userservice.onrLocal changesShelfConsole xLog Xenv.local aon@.liminnvDehuaCommandinhn annlConcole/Commanddpho loadina nhn confialg SoftPhoneManager.php app/Component/Twilio/Conference/ConferenceManag© TextMessagingService.php app/Services/TelephonyUnversioned Files 9 filesE.env.nikilocal appE.env.other app© CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/R6 favicon.ico publicEids.txt aprTraw saL querv.sal app© SimulateWebhooksCommand.php app/Console/Commands/Crm/HubspotM+ WEBHOOK FILTERING IMPLEMENTATION.md appPatch succoccfullv annlied (15 minutes aao)synerorlannatpnp©PlaybackController.phppnp api.phpC) CreateSmsSentEvent.php(C) PlanhatActivityListener.pho(C)AskAnythingPromptService.php© AutomatedReportsRepository.php(C) AutomatedReportsCommand.phpphp api v2.phpC) RequestGenerateReportJob.pho(C) AutomatedReportResult.php© AutomatedReport.phpclass UserAutomatedReportsController extends ControllerBI4NLAY7а (61pubulc tunccion -_conscruceprivate readonly AutomatedReportsRepository $automatedReportsRepositoryprivace readonly Aucomareckeporcsservice saucomareakeportsservice.private readonly Apikesponseservice sapikesponseservice,private readonly kesponse sresponse.private readonly PlanhatService $planhatService,{...1PosTlaoi/vilautomated-reports/interest 1 usagepublic function trackInterest(Request Srequest): JsonResponsef...?* othrows ApplicationExceotionG-Taoi/vlautomated-renortsnublic function List(Request Srequest): IsonResnonsef.}DELETE lanilv1/automated-renorts/uuidpublic function delete(Request Srequest, string $uuid): JsonResponset...}+ → @ Side-by-side viewer ~Do not ianore vHighlight words 13 g ?81aee7aadScontact = nulliCctane = null.Sopportunity = null;/ Setup services.ScrmService = $this->crmProviderRegistry->get(Steam->crm->provider):if (! Suser->isCrmRequiredo){ScrmService->setUser(Suser->team->owner):} else {scrmservice->serusersuser=custom.log= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]© TextMessagingService.php X A console [EU]A console [STAGING]stohenamespace Jininny services lelephony>use ...class TextMessaqngServiceorivate ?Team steam = nulu3 usadesorivate ?TwilioClient Stwilionlient = nultpublic function __construct(private readonly ProviderRegistry $providerRegistry,private readonly ActivityService SactivityService,private readonly Webhook SurlGeneratorprivate readonly TwilioClientBuilder $twilioClientBuilder,* Othrows ConfigurationExceptionpublic function setTeam(Team $team): voidsth1s->team = steam:Sthis-›twilioClient = Sthis->twilioClientBuilder->build(Steam):* Athrows \Exceptionoublic function sendUser Sfrom. strina Sto. strina Smessage): Messagelnstancelcurrent versionScontact = null;$stage = null;Sopportunity = null;try {ScrmResolver = app(Crm0wnerResolver::class,'team' => $team'integrationAdmin' => $usen'providerSlug' => $team->getCrmConfiqurationO->qetProviderNameOScrmService = ScrmResolver->prepareCrmService0:} catch (\Throwable Sthrowable){100% 52. Fri 22 May 14:02:59AskJiminnyReportActivityServiceTest vCascadeInvestigate Foreign KeSalestorce Token Fallb+0 ..122 V1 V1 AVThe file is still off lot of warning just see what is wrongThoughtsInought tor 1sI see the issue - the try-catch structure is broken. The catch block on line 147 for SocialAccountTokenInvalidExceptionhas no matching try block because the CRM usage code (lines 115-146) is not wrapped in a try block.• TextMessagingService.phrThoughtsnckcalonThoughtsFixed the trv-catch olock structure in TextMessagingService, The issue was that the catch olock tor Social AccountTokeninvalidException (line 147) had no matching try block - the CRM usage code wasn't wrapped in a try block after I added the1. SoftPhoneManager.php - Added CrmOwnerResolver fallback for both outbound and inbound Twilio calls2. TextMessagingService.php - Added CrmOwnerResolver fallback for both buildActivity and convertCustomerToCouncrylode metnoas, with proper try-catch structureBoth imolementations now:• First try CrmOwnerResolver to find an active Salesforce token from the organization• If that fails, fall back to the original direct user assignment pattern• Let existing outer catch blocks handle any Socia AccountTokenInvalidException by settina CRM data to nullThis ensures Twilio calls will use another active Salesforce token when the admin token expires, preventing "UnknownGal .Review all places in the code where we could use CrmOwnerResolver to make sure that service2 differencasW Windsurf Teamc1-1.UTE.8io 4 spaces...
|
70990
|
NULL
|
NULL
|
NULL
|
|
70993
|
2550
|
16
|
2026-05-22T11:03:01.052009+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447781052_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7460324410827463904
|
-8204420481061508160
|
typing_pause
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
SlackFileEditViewGoHistoryWindowHelpAPP (DOCKER₴81DEV (-zsh)O $82APP (-zsh)tests/Unit/Services/Activity/RingCentral/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/TwilioVideoMetadataHandlerTest.phptests/Unit/Services/Kiosk/AutomatedReports/AutomatedReportsServiceTest.phptests/Unit/Services/Mail/0ffice/EmailApiClientTest.phptests/Unit/Services/Mail/TextRelayServiceTest.phptests/Unit/Services/RecallAI/RecallAIServiceTest.php79 files changed, 4254 insertions(+), 2020 deletions(-)create mode 100644 .github/claude-reviewer/no-ticket-warning.txtcreate mode 100644 .github/claude-reviewer/scripts/fetch-jira-context.mjsdelete mode 100644 app/Component/ES/Processor/BatchStatusInterface.phpcreatemode 100644 app/Component/ES/Processor/RedisEntityExtractor.phpdelete mode100644 app/Component/ES/Processor/Traits/WorkerIdTrait.phpcreate mode 100644 app/Component/ES/QueuePriorityEnum.phpTrginusWorker/aTrai+: Phpcreate mode 100644 front-end/src/components/DealInsights/Modals/__tests__/AskAnythingModacreate mode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Asdeletemode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Ascreatemode 100644 tests/Unit/Component/ES/Processor/RedisEntityExtractorTest.phpdelete mode 100644 tests/Unit/Component/ES/Processor/Traits/WorkerIdTraitTest.phpcreate mode 100644 tests/Unit/Component/ES/QueuePriorityEnumTest.phpcreate mode 100644 tests/Unit/Notifications/Activities/SmsReceivedTest.phpcreate mode 100644 tests/Unit/Services/Mail/TextRelayServiceTest.phplukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20963-fix-imporSwitched to a new branch 'JY-20963-fix-import-on-deleted-entity'lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20963-fix-import-on-deleted-entdocker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn moreat [URL_WITH_CREDENTIALS] (JY-20963-fix-import-on-deleted-ent|docker exec -it docker_lamp_1./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.PHPruntime: 8.3.30Running analysis on 7 cores with 10 files perprocess.Parallel runner is an experimental feature and may be unstable, use itat your ownrisk.Loaded config default from".php-cs-fixer.dist.php"5691/5691100%Fixed 0 of 5691 files in 96.077 seconds, 67.00 MBmemory used•HomeDMsActivityFilesLater+ED→Jiminny ...& jiminny-x-integrati...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# happy_birthday# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messagesP. Galya Dimitrova ". Nikolay YankovP. Aneliya Angelova. Stoyan Tanev& James Graham> 0(all100% С8 • Fri 22 May 14:03:00Describe what you are looking for# releases8 226 0• MessagesProject: appC FilesBookmarksM/kan.Today ~J26+10:26:05Tag:View JobGitHub APP1:27 PM4 new commits pushed tomaster byTodorStamatovJiminnycbf9b72b - JY-20955: fix calendar eventduplication checkafe8dceg - Merge branch 'master' into JY-20955-multiple-calendars-events218a8602 - Merge branch 'master' into JY-20955-multiple-calendars-eventsbe560cbf - Merge pull request #12119 fromjiminny/JY-20955-multiple-calendars-eventsjiminny/app | Added by GitHubNewCircleCl APP 1:53 PMDeployment Successful!Project: appWhen:05/22/202610:53:15Tag:View JobMessage #releases+Aa..•...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
70994
|
2550
|
17
|
2026-05-22T11:03:03.474914+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447783474_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5111928977143741995
|
-3204935344002590708
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
70993
|
NULL
|
NULL
|
NULL
|
|
70995
|
2551
|
19
|
2026-05-22T11:03:03.360173+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447783360_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"bounds":{"left":0.390625,"top":0.2490024,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.40226063,"top":0.2490024,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.4119016,"top":0.24740623,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.4192154,"top":0.24740623,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"bounds":{"left":0.6911569,"top":0.10055866,"width":0.009973404,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.703125,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.7124335,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.72140956,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7287234,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","depth":4,"bounds":{"left":0.4481383,"top":0.09736632,"width":0.36269948,"height":0.90263367},"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8419801864614017883
|
-4357855742655358964
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
70996
|
2551
|
20
|
2026-05-22T11:03:07.791250+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447787791_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"bounds":{"left":0.390625,"top":0.2490024,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.40226063,"top":0.2490024,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.4119016,"top":0.24740623,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.4192154,"top":0.24740623,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"bounds":{"left":0.6911569,"top":0.10055866,"width":0.009973404,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.703125,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.7124335,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.72140956,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7287234,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","depth":4,"bounds":{"left":0.4481383,"top":0.09736632,"width":0.36269948,"height":0.90263367},"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5111928977143741995
|
-3204935344002590708
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
70995
|
NULL
|
NULL
|
NULL
|
|
70997
|
2550
|
18
|
2026-05-22T11:03:09.456387+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447789456_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
2747973124440183400
|
-4357855742655358964
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
70998
|
2550
|
19
|
2026-05-22T11:03:12.468869+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447792468_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
2544460550312045128
|
-3772886318662960627
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error...
|
70997
|
NULL
|
NULL
|
NULL
|
|
70999
|
2550
|
20
|
2026-05-22T11:03:14.345641+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447794345_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5111928977143741995
|
-3204935344002590708
|
typing_pause
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
71000
|
2551
|
21
|
2026-05-22T11:03:25.588679+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447805588_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormFV faVsco.js°9 master kroledey© InsightsSe PhostormFV faVsco.js°9 master kroledey© InsightsService.php© NumberAllocator.php1extmessagingservice.pngc I willoclient.onpcIwlloclientbullder.pnpcIwilloservice.ono•D UserPilot_ WebhookC AbstractService.php© ActivitvProviderFactory.php©) [EMAIL]© ConferenceService.phpC)InsiahtSeatService.oho© InstantMeetingService.php© IntercomService.php© IpapiClient.php(c) Inan Service nhnl© ParticipantShareService.php@ PlanhatService.php© PlaybackService.phpPlaybackVideoOnlyService.php© PlaybookCategoryService.php© PlaylistGeneratorinterface.phpkesolveleamermeonnection.ong© SimpleThrottleService.php@ ClackService.php© SocialAccountService.php© SoftPhoneService.php© TeamDeactivatedService.php© TeamOwnerService.php123 19)c) Teamservice.php© TranscodeParameterResolver.phpc Userservice.onrLocal changesShelfConsole xLog Xenv.local aon@.liminnvDehuaCommandinhn annlConcole/Commanddpho loadina nhn confialg SoftPhoneManager.php app/Component/Twilio/Conference/ConferenceManag© TextMessagingService.php app/Services/TelephonyUnversioned Files 9 filesE.env.nikilocal appE.env.other app© CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/R6 favicon.ico publicEids.txt aprTraw saL querv.sal appC) SimulateWebhooksCommand.oho app/Console/Commands/Crm/HubspotM+ WEBHOOK FILTERING IMPLEMENTATION.md appPatch succoccfullv annlied (16 minutes aao)synerorlannatpnp©PlaybackController.phppnp api.phpC) CreateSmsSentEvent.php(C) PlanhatActivityListener.pho(C)AskAnythingPromptService.php© AutomatedReportsRepository.php(C) AutomatedReportsCommand.phpphp api v2.phpC) RequestGenerateReportJob.pho(C) AutomatedReportResult.php© AutomatedReport.phpclass UserAutomatedReportsController extends ControllerBI4NLAY7а (61pubulc tunccion -_conscruceprivate readonly AutomatedReportsRepository $automatedReportsRepositoryprivace readonly Aucomareckeporcsservice saucomareakeportsservice.private readonly Apikesponseservice sapikesponseservice,private readonly kesponse sresponse.private readonly PlanhatService $planhatService,{...1PosTlaoi/vilautomated-reports/interest 1 usagepublic function trackInterest(Request Srequest): JsonResponsef...,* othrows ApplicationExceotionG-Taoi/vlautomated-renortsnublic function List(Request Srequest): IsonResnonsef.}DELETE lanilv1/automated-renorts/uuidpublic function delete(Request Srequest, string $uuid): JsonResponset...*+ → @ Side-by-side viewer ~Do not ianore vHighlight words 13 g ?81aee7aadScontact = nulliCctane = null.Sopportunity = null;/ Setup services.ScrmService = $this->crmProviderRegistry->get(Steam->crm->provider):if (! Suser->isCrmRequiredo){ScrmService->setUser(Suser->team->owner):} else {scrmservice->serusersuser=custom.log= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]© TextMessagingService.php X A console [EU]A console [STAGING]stohenamespace Jininny services lelephony>use ...class TextMessaqngServiceorivate ?Team steam = nulu3 usadesorivate ?TwilioClient Stwilionlient = nultpublic function __construct(private readonly ProviderRegistry $providerRegistry,private readonly ActivityService SactivityService,private readonly Webhook SurlGeneratorprivate readonly TwilioClientBuilder $twilioClientBuilder,* Othrows ConfigurationExceptionpublic function setTeam(Team $team): voidsth1s->team = steam:Sthis-›twilioClient = Sthis->twilioClientBuilder->build(Steam):* Athrows \Exceptionoublic function sendUser Sfrom. strina Sto. strina Smessage): Messagelnstancelcurrent versionScontact = null;$stage = null;Sopportunity = null;try {ScrmResolver = app(Crm0wnerResolver::class,'team' => $team'integrationAdmin' => $user'providerSlug' => $team->getCrmConfiqurationO->qetProviderNameOScrmService = ScrmResolver->prepareCrmService0:} catch (\Throwable Sthrowable){100% 2. Fri 22 May 14:03:25AskJiminnyReportActivityServiceTest vCascadeInvestigate Foreign KeSalestorce Token Fallb+0 ..122 V1 V1 AVThe file is still off lot of warning just see what is wrongThoughtsInought tor 1sI see the issue - the try-catch structure is broken. The catch block on line 147 for SocialAccountTokenInvalidExceptionhas no matching try block because the CRM usage code (lines 115-146) is not wrapped in a try block.• TextMessagingService.phrnskealoneFixed the trv-catch olock structure in TextMessagingService, The issue was that the catch olock tor Social AccountTokeninvalidException (line 147) had no matching try block - the CRM usage code wasn't wrapped in a try block after I added the1. SoftPhoneManager.php - Added CrmOwnerResolver fallback for both outbound and inbound Twilio calls2. TextMessagingService.php - Added CrmOwnerResolver fallback for both buildActivity and convertCustomerToCouncrylode metnoas, with proper try-catch structureBoth imolementations now:• First try CrmOwnerResolver to find an active Salesforce token from the organization• If that fails, fall back to the original direct user assignment pattern• Let existing outer catch blocks handle any Socia AccountTokenInvalidException by settina CRM data to nullThis ensures Twilio calls will use another active Salesforce token when the admin token expires, preventing "UnknownPeview all nlaces in the code where we could uce CrmOwnerPecolver to make cure that cervice worke even in the cacethere is no token valid2 differencasW Windsurf Teamc1-1.UTE.8io 4 spaces...
|
NULL
|
-8918626944508571342
|
NULL
|
typing_pause
|
ocr
|
NULL
|
PhostormFV faVsco.js°9 master kroledey© InsightsSe PhostormFV faVsco.js°9 master kroledey© InsightsService.php© NumberAllocator.php1extmessagingservice.pngc I willoclient.onpcIwlloclientbullder.pnpcIwilloservice.ono•D UserPilot_ WebhookC AbstractService.php© ActivitvProviderFactory.php©) [EMAIL]© ConferenceService.phpC)InsiahtSeatService.oho© InstantMeetingService.php© IntercomService.php© IpapiClient.php(c) Inan Service nhnl© ParticipantShareService.php@ PlanhatService.php© PlaybackService.phpPlaybackVideoOnlyService.php© PlaybookCategoryService.php© PlaylistGeneratorinterface.phpkesolveleamermeonnection.ong© SimpleThrottleService.php@ ClackService.php© SocialAccountService.php© SoftPhoneService.php© TeamDeactivatedService.php© TeamOwnerService.php123 19)c) Teamservice.php© TranscodeParameterResolver.phpc Userservice.onrLocal changesShelfConsole xLog Xenv.local aon@.liminnvDehuaCommandinhn annlConcole/Commanddpho loadina nhn confialg SoftPhoneManager.php app/Component/Twilio/Conference/ConferenceManag© TextMessagingService.php app/Services/TelephonyUnversioned Files 9 filesE.env.nikilocal appE.env.other app© CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/R6 favicon.ico publicEids.txt aprTraw saL querv.sal appC) SimulateWebhooksCommand.oho app/Console/Commands/Crm/HubspotM+ WEBHOOK FILTERING IMPLEMENTATION.md appPatch succoccfullv annlied (16 minutes aao)synerorlannatpnp©PlaybackController.phppnp api.phpC) CreateSmsSentEvent.php(C) PlanhatActivityListener.pho(C)AskAnythingPromptService.php© AutomatedReportsRepository.php(C) AutomatedReportsCommand.phpphp api v2.phpC) RequestGenerateReportJob.pho(C) AutomatedReportResult.php© AutomatedReport.phpclass UserAutomatedReportsController extends ControllerBI4NLAY7а (61pubulc tunccion -_conscruceprivate readonly AutomatedReportsRepository $automatedReportsRepositoryprivace readonly Aucomareckeporcsservice saucomareakeportsservice.private readonly Apikesponseservice sapikesponseservice,private readonly kesponse sresponse.private readonly PlanhatService $planhatService,{...1PosTlaoi/vilautomated-reports/interest 1 usagepublic function trackInterest(Request Srequest): JsonResponsef...,* othrows ApplicationExceotionG-Taoi/vlautomated-renortsnublic function List(Request Srequest): IsonResnonsef.}DELETE lanilv1/automated-renorts/uuidpublic function delete(Request Srequest, string $uuid): JsonResponset...*+ → @ Side-by-side viewer ~Do not ianore vHighlight words 13 g ?81aee7aadScontact = nulliCctane = null.Sopportunity = null;/ Setup services.ScrmService = $this->crmProviderRegistry->get(Steam->crm->provider):if (! Suser->isCrmRequiredo){ScrmService->setUser(Suser->team->owner):} else {scrmservice->serusersuser=custom.log= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]© TextMessagingService.php X A console [EU]A console [STAGING]stohenamespace Jininny services lelephony>use ...class TextMessaqngServiceorivate ?Team steam = nulu3 usadesorivate ?TwilioClient Stwilionlient = nultpublic function __construct(private readonly ProviderRegistry $providerRegistry,private readonly ActivityService SactivityService,private readonly Webhook SurlGeneratorprivate readonly TwilioClientBuilder $twilioClientBuilder,* Othrows ConfigurationExceptionpublic function setTeam(Team $team): voidsth1s->team = steam:Sthis-›twilioClient = Sthis->twilioClientBuilder->build(Steam):* Athrows \Exceptionoublic function sendUser Sfrom. strina Sto. strina Smessage): Messagelnstancelcurrent versionScontact = null;$stage = null;Sopportunity = null;try {ScrmResolver = app(Crm0wnerResolver::class,'team' => $team'integrationAdmin' => $user'providerSlug' => $team->getCrmConfiqurationO->qetProviderNameOScrmService = ScrmResolver->prepareCrmService0:} catch (\Throwable Sthrowable){100% 2. Fri 22 May 14:03:25AskJiminnyReportActivityServiceTest vCascadeInvestigate Foreign KeSalestorce Token Fallb+0 ..122 V1 V1 AVThe file is still off lot of warning just see what is wrongThoughtsInought tor 1sI see the issue - the try-catch structure is broken. The catch block on line 147 for SocialAccountTokenInvalidExceptionhas no matching try block because the CRM usage code (lines 115-146) is not wrapped in a try block.• TextMessagingService.phrnskealoneFixed the trv-catch olock structure in TextMessagingService, The issue was that the catch olock tor Social AccountTokeninvalidException (line 147) had no matching try block - the CRM usage code wasn't wrapped in a try block after I added the1. SoftPhoneManager.php - Added CrmOwnerResolver fallback for both outbound and inbound Twilio calls2. TextMessagingService.php - Added CrmOwnerResolver fallback for both buildActivity and convertCustomerToCouncrylode metnoas, with proper try-catch structureBoth imolementations now:• First try CrmOwnerResolver to find an active Salesforce token from the organization• If that fails, fall back to the original direct user assignment pattern• Let existing outer catch blocks handle any Socia AccountTokenInvalidException by settina CRM data to nullThis ensures Twilio calls will use another active Salesforce token when the admin token expires, preventing "UnknownPeview all nlaces in the code where we could uce CrmOwnerPecolver to make cure that cervice worke even in the cacethere is no token valid2 differencasW Windsurf Teamc1-1.UTE.8io 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
71001
|
2550
|
21
|
2026-05-22T11:03:25.724480+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447805724_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpAPP (DOCKERDEV SlackFileEditViewGoHistoryWindowHelpAPP (DOCKERDEV (-zsh)O $82APP (-zsh)tests/Unit/Services/Activity/RingCentral/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/TwilioVideoMetadataHandlerTest.phptests/Unit/Services/Kiosk/AutomatedReports/AutomatedReportsServiceTest.phptests/Unit/Services/Mail/0ffice/EmailApiClientTest.phptests/Unit/Services/Mail/TextRelayServiceTest.phptests/Unit/Services/RecallAI/RecallAIServiceTest.php79 files changed, 4254 insertions(+), 2020 deletions(-)create mode 100644 .github/claude-reviewer/no-ticket-warning.txtcreate mode 100644 .github/claude-reviewer/scripts/fetch-jira-context.mjsdelete mode 100644 app/Component/ES/Processor/BatchStatusInterface.phpcreatemode 100644 app/Component/ES/Processor/RedisEntityExtractor.phpdelete mode100644 app/Component/ES/Processor/Traits/WorkerIdTrait.phpcreate mode 100644 app/Component/ES/QueuePriorityEnum.phpTrginusWorker/aTrai+: Phpcreate mode 100644 front-end/src/components/DealInsights/Modals/__tests__/AskAnythingModacreate mode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Asdeletemode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Ascreatemode 100644 tests/Unit/Component/ES/Processor/RedisEntityExtractorTest.phpdelete mode 100644 tests/Unit/Component/ES/Processor/Traits/WorkerIdTraitTest.phpcreate mode 100644 tests/Unit/Component/ES/QueuePriorityEnumTest.phpcreate mode 100644 tests/Unit/Notifications/Activities/SmsReceivedTest.phpcreate mode 100644 tests/Unit/Services/Mail/TextRelayServiceTest.phplukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20963-fix-imporSwitched to a new branch 'JY-20963-fix-import-on-deleted-entity'lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20963-fix-import-on-deleted-entdocker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn moreat [URL_WITH_CREDENTIALS] (JY-20963-fix-import-on-deleted-ent|docker exec -it docker_lamp_1./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.PHPruntime: 8.3.30Running analysis on 7 cores with 10 files perprocess.Parallel runner is an experimental feature and may be unstable, use itat your ownrisk.Loaded config default from".php-cs-fixer.dist.php"5691/5691100%Fixed 0 of 5691 files in 96.077 seconds, 67.00 MBmemory used•HomeDMsActivityFilesLater+ED→Jiminny ...& jiminny-x-integrati...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# happy_birthday# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messagesP. Galya Dimitrova ". Nikolay YankovP. Aneliya Angelova. Stoyan Tanev& James Graham> 0(all100% С8 • Fri 22 May 14:03:25Describe what you are looking for# releases8 226 0• MessagesProject: appC FilesBookmarksM/kan.Today ~J26+10:26:05Tag:View JobGitHub APP1:27 PM4 new commits pushed tomaster byTodorStamatovJiminnycbf9b72b - JY-20955: fix calendar eventduplication checkafe8dceg - Merge branch 'master' into JY-20955-multiple-calendars-events218a8602 - Merge branch 'master' into JY-20955-multiple-calendars-eventsbe560cbf - Merge pull request #12119 fromjiminny/JY-20955-multiple-calendars-eventsjiminny/app | Added by GitHubNewCircleCl APP 1:53 PMDeployment Successful!Project: appWhen:05/22/202610:53:15Tag:View JobMessage #releases+Aa..•...
|
NULL
|
8277879331132029925
|
NULL
|
typing_pause
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpAPP (DOCKERDEV SlackFileEditViewGoHistoryWindowHelpAPP (DOCKERDEV (-zsh)O $82APP (-zsh)tests/Unit/Services/Activity/RingCentral/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/TwilioVideoMetadataHandlerTest.phptests/Unit/Services/Kiosk/AutomatedReports/AutomatedReportsServiceTest.phptests/Unit/Services/Mail/0ffice/EmailApiClientTest.phptests/Unit/Services/Mail/TextRelayServiceTest.phptests/Unit/Services/RecallAI/RecallAIServiceTest.php79 files changed, 4254 insertions(+), 2020 deletions(-)create mode 100644 .github/claude-reviewer/no-ticket-warning.txtcreate mode 100644 .github/claude-reviewer/scripts/fetch-jira-context.mjsdelete mode 100644 app/Component/ES/Processor/BatchStatusInterface.phpcreatemode 100644 app/Component/ES/Processor/RedisEntityExtractor.phpdelete mode100644 app/Component/ES/Processor/Traits/WorkerIdTrait.phpcreate mode 100644 app/Component/ES/QueuePriorityEnum.phpTrginusWorker/aTrai+: Phpcreate mode 100644 front-end/src/components/DealInsights/Modals/__tests__/AskAnythingModacreate mode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Asdeletemode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Ascreatemode 100644 tests/Unit/Component/ES/Processor/RedisEntityExtractorTest.phpdelete mode 100644 tests/Unit/Component/ES/Processor/Traits/WorkerIdTraitTest.phpcreate mode 100644 tests/Unit/Component/ES/QueuePriorityEnumTest.phpcreate mode 100644 tests/Unit/Notifications/Activities/SmsReceivedTest.phpcreate mode 100644 tests/Unit/Services/Mail/TextRelayServiceTest.phplukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20963-fix-imporSwitched to a new branch 'JY-20963-fix-import-on-deleted-entity'lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20963-fix-import-on-deleted-entdocker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn moreat [URL_WITH_CREDENTIALS] (JY-20963-fix-import-on-deleted-ent|docker exec -it docker_lamp_1./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.PHPruntime: 8.3.30Running analysis on 7 cores with 10 files perprocess.Parallel runner is an experimental feature and may be unstable, use itat your ownrisk.Loaded config default from".php-cs-fixer.dist.php"5691/5691100%Fixed 0 of 5691 files in 96.077 seconds, 67.00 MBmemory used•HomeDMsActivityFilesLater+ED→Jiminny ...& jiminny-x-integrati...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# happy_birthday# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messagesP. Galya Dimitrova ". Nikolay YankovP. Aneliya Angelova. Stoyan Tanev& James Graham> 0(all100% С8 • Fri 22 May 14:03:25Describe what you are looking for# releases8 226 0• MessagesProject: appC FilesBookmarksM/kan.Today ~J26+10:26:05Tag:View JobGitHub APP1:27 PM4 new commits pushed tomaster byTodorStamatovJiminnycbf9b72b - JY-20955: fix calendar eventduplication checkafe8dceg - Merge branch 'master' into JY-20955-multiple-calendars-events218a8602 - Merge branch 'master' into JY-20955-multiple-calendars-eventsbe560cbf - Merge pull request #12119 fromjiminny/JY-20955-multiple-calendars-eventsjiminny/app | Added by GitHubNewCircleCl APP 1:53 PMDeployment Successful!Project: appWhen:05/22/202610:53:15Tag:View JobMessage #releases+Aa..•...
|
70999
|
NULL
|
NULL
|
NULL
|
|
71002
|
2551
|
22
|
2026-05-22T11:03:59.337331+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447839337_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2796147080355312063
|
-8636637127315567163
|
idle
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
PhostormFV faVsco.js°9 master kroledey© InsightsService.php© NumberAllocator.php1extmessagingservice.pngc I willoclient.onpcIwlloclientbullder.pnpcIwilloservice.ono•D UserPilot_ WebhookC AbstractService.php© ActivitvProviderFactory.php©) [EMAIL]© ConferenceService.phpC)InsiahtSeatService.oho© InstantMeetingService.php© IntercomService.php© IpapiClient.php(c) Inan Service nhnl© ParticipantShareService.php@ PlanhatService.php© PlaybackService.phpPlaybackVideoOnlyService.php© PlaybookCategoryService.php© PlaylistGeneratorinterface.phpkesolveleamermeonnection.ong© SimpleThrottleService.php@ ClackService.php© SocialAccountService.php© SoftPhoneService.php© TeamDeactivatedService.php© TeamOwnerService.php123 19)c) Teamservice.php© TranscodeParameterResolver.phpc Userservice.onrLocal changesShelfConsole xLog Xenv.local aon@.liminnvDehuaCommandinhn ann/ConcolelCommandepho loadina nhn confialg SoftPhoneManager.php app/Component/Twilio/Conference/ConferenceManag© TextMessagingService.php app/Services/TelephonyUnversioned Files 9 filesE.env.nikilocal appE.env.other app© CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/R6 favicon.ico publicEids.txt aprTraw saL querv.sal appC) SimulateWebhooksCommand.oho app/Console/Commands/Crm/HubspotM+ WEBHOOK FILTERING IMPLEMENTATION.md appPatch succoccfullv annlied (16 minutes aao)synerorlannatpnp©PlaybackController.phppnp api.phpC) CreateSmsSentEvent.php(C) PlanhatActivityListener.pho(C)AskAnythingPromptService.php© AutomatedReportsRepository.php(C) AutomatedReportsCommand.phpphp api v2.phpC) RequestGenerateReportJob.pho(C) AutomatedReportResult.php© AutomatedReport.phpclass UserAutomatedReportsController extends ControllerBI4NLAY70 (61pubulc tunccion -_conscruceprivate readonly AutomatedReportsRepository $automatedReportsRepository.privace readonly Aucomareckeporcsservice saucomareakeportsservice.private readonly Apikesponseservice sapikesponseservice,private readonly kesponse sresponse.private readonly PlanhatService $planhatService,{...1PosTlaoi/vilautomated-reports/interest 1 usagepublic function trackInterest(Request Srequest): JsonResponsef...,* othrows ApplicationExceotionG-Taoi/vlautomated-renortsnublic function List(Request Srequest): JsonResnonsef…}DELETE lanilv1/automated-renorts/uuidpublic function delete(Request Srequest, string $uuid): JsonResponsel...*+ → @ Side-by-side viewer ~Do not ianore vHighlight words 13 g ?81aee7aadScontact = nulliCctane = null.Sopportunity = null;/ Setup services.ScrmService = $this->crmProviderRegistry->get(Steam->crm->provider):if (! Suser->isCrmRequiredo){ScrmService->setUser(Suser->team->owner):} else {scrmservice->serusersuser=custom.log= laravel.log« SF jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]© TextMessagingService.php X A console (EU]A console [STAGING]stohenamespace Jininny services lelephony>use ...class TextMessaqngServiceorivate ?Team steam = nulu3 usadesorivate ?TwilioClient Stwilionlient = nultpublic function __construct(private readonly ProviderRegistry $providerRegistry,private readonly ActivityService SactivityService,private readonly Webhook SurlGeneratorprivate readonly TwilioClientBuilder $twilioClientBuilder,* Othrows ConfigurationExceptionpublic function setTeam(Team $team): voidsth1s->team = steam:Sthis-›twilioClient = Sthis->twilioClientBuilder->build(Steam):* Athrows \Exception4ck anvthina (8eA1)oublic function sendUser Sfrom. strina Sto. strina Smessage): Messagelnstancelcurrent versionScontact = null.Cctano = null.Sopportunity = null;try {ScrmResolver = app(Crm0wnerResolver::class,'team' => $team!'integrationAdmin' => $user'providerSlug' => $team->getCrmConfiqurationO->qetProviderNameOScrmService = ScrmResolver->prepareCrmServiceO:} catch (\Throwable Sthrowable) {S0 hll100% L2• Fri 22 May 14:03:58AskJiminnyReportActivityServiceTest vCascadeInvestigate Foreign KeSalestorce Token Fa+0 ..122 V1 V1 AVin the code where we could use CrmOwnerResolver to make sure that service works even in the caseThoughtsSearched crmProviderRegistry->get|providerRegistry->get.*crm|ProviderRegistry.*->get\( in app (78) ›Thought for 4s >searcned crmservice->setuser|crmservices=sstis->providerkegistry->ger/crmservices =sotis->crmProvider.2 differencasW Windsurf Teams1-1.UTE.9io 4 spaces...
|
71000
|
NULL
|
NULL
|
NULL
|
|
71003
|
2550
|
22
|
2026-05-22T11:04:01.290461+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447841290_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
5222591262487654398
|
-8636637129462003327
|
idle
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
SlackFileEditViewGoHistoryWindowHelpAPP (DOCKERDEV (-zsh)O $82APP (-zsh)tests/Unit/Services/Activity/RingCentral/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/TwilioVideoMetadataHandlerTest.phptests/Unit/Services/Kiosk/AutomatedReports/AutomatedReportsServiceTest.phptests/Unit/Services/Mail/0ffice/EmailApiClientTest.phptests/Unit/Services/Mail/TextRelayServiceTest.phptests/Unit/Services/RecallAI/RecallAIServiceTest.php79 files changed, 4254 insertions(+), 2020 deletions(-)create mode 100644 .github/claude-reviewer/no-ticket-warning.txtcreate mode 100644 .github/claude-reviewer/scripts/fetch-jira-context.mjsdelete mode 100644 app/Component/ES/Processor/BatchStatusInterface.phpcreatemode 100644 app/Component/ES/Processor/RedisEntityExtractor.phpdelete mode100644 app/Component/ES/Processor/Traits/WorkerIdTrait.phpcreate mode 100644 app/Component/ES/QueuePriorityEnum.phpTrginusWorker/aTrai+: Phpcreate mode 100644 front-end/src/components/DealInsights/Modals/__tests__/AskAnythingModacreate mode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Asdeletemode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Ascreatemode 100644 tests/Unit/Component/ES/Processor/RedisEntityExtractorTest.phpdelete mode 100644 tests/Unit/Component/ES/Processor/Traits/WorkerIdTraitTest.phpcreate mode 100644 tests/Unit/Component/ES/QueuePriorityEnumTest.phpcreate mode 100644 tests/Unit/Notifications/Activities/SmsReceivedTest.phpcreate mode 100644 tests/Unit/Services/Mail/TextRelayServiceTest.phplukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20963-fix-imporSwitched to a new branch 'JY-20963-fix-import-on-deleted-entity'lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20963-fix-import-on-deleted-entdocker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn moreat [URL_WITH_CREDENTIALS] (JY-20963-fix-import-on-deleted-ent|docker exec -it docker_lamp_1./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.PHPruntime: 8.3.30Running analysis on 7 cores with 10 files perprocess.Parallel runner is an experimental feature and may be unstable, use itat your ownrisk.Loaded config default from".php-cs-fixer.dist.php"5691/5691100%Fixed 0 of 5691 files in 96.077 seconds, 67.00 MBmemory used•HomeDMsActivityFilesLater+ED→Jiminny ...& jiminny-x-integrati...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# happy_birthday# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messagesP. Galya Dimitrova ". Nikolay YankovP. Aneliya Angelova. Stoyan Tanev& James Graham> 0(all100% С8 • Fri 22 May 14:04:00Describe what you are looking for# releases8 226 0• MessagesProject: appC FilesBookmarksM/kan.Today ~J26+10:26:05Tag:View JobGitHub APP1:27 PM4 new commits pushed tomaster byTodorStamatovJiminnycbf9b72b - JY-20955: fix calendar eventduplication checkafe8dceg - Merge branch 'master' into JY-20955-multiple-calendars-events218a8602 - Merge branch 'master' into JY-20955-multiple-calendars-eventsbe560cbf - Merge pull request #12119 fromjiminny/JY-20955-multiple-calendars-eventsjiminny/app | Added by GitHubNewCircleCl APP 1:53 PMDeployment Successful!Project: appWhen:05/22/202610:53:15Tag:View JobMessage #releases+Aa..•...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
71004
|
NULL
|
0
|
2026-05-22T11:04:32.457311+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447872457_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"bounds":{"left":0.390625,"top":0.2490024,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.40226063,"top":0.2490024,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.4119016,"top":0.24740623,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.4192154,"top":0.24740623,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2756535304298618912
|
-2619120939016537587
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
71005
|
NULL
|
0
|
2026-05-22T11:04:33.900612+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447873900_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4235983745889776938
|
-8204421443435123770
|
idle
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
SlackFileEditViewGoHistoryWindowHelpAPP (DOCKERDEV (-zsh)O $82APP (-zsh)tests/Unit/Services/Activity/RingCentral/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/TwilioVideoMetadataHandlerTest.phptests/Unit/Services/Kiosk/AutomatedReports/AutomatedReportsServiceTest.phptests/Unit/Services/Mail/0ffice/EmailApiClientTest.phptests/Unit/Services/Mail/TextRelayServiceTest.phptests/Unit/Services/RecallAI/RecallAIServiceTest.php79 files changed, 4254 insertions(+), 2020 deletions(-)create mode 100644 .github/claude-reviewer/no-ticket-warning.txtcreate mode 100644 .github/claude-reviewer/scripts/fetch-jira-context.mjsdelete mode 100644 app/Component/ES/Processor/BatchStatusInterface.phpcreatemode 100644 app/Component/ES/Processor/RedisEntityExtractor.phpdelete mode100644 app/Component/ES/Processor/Traits/WorkerIdTrait.phpcreate mode 100644 app/Component/ES/QueuePriorityEnum.phpTrginusWorker/aTrai+: Phpcreate mode 100644 front-end/src/components/DealInsights/Modals/__tests__/AskAnythingModacreate mode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Asdeletemode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Ascreatemode 100644 tests/Unit/Component/ES/Processor/RedisEntityExtractorTest.phpdelete mode 100644 tests/Unit/Component/ES/Processor/Traits/WorkerIdTraitTest.phpcreate mode 100644 tests/Unit/Component/ES/QueuePriorityEnumTest.phpcreate mode 100644 tests/Unit/Notifications/Activities/SmsReceivedTest.phpcreate mode 100644 tests/Unit/Services/Mail/TextRelayServiceTest.phplukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20963-fix-imporSwitched to a new branch 'JY-20963-fix-import-on-deleted-entity'lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20963-fix-import-on-deleted-entdocker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn moreat [URL_WITH_CREDENTIALS] (JY-20963-fix-import-on-deleted-ent|docker exec -it docker_lamp_1./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.PHPruntime: 8.3.30Running analysis on 7 cores with 10 files perprocess.Parallel runner is an experimental feature and may be unstable, use itat your ownrisk.Loaded config default from".php-cs-fixer.dist.php"5691/5691100%Fixed 0 of 5691 files in 96.077 seconds, 67.00 MBmemory used•HomeDMsActivityFilesLater+ED→Jiminny ...& jiminny-x-integrati...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# happy_birthday# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messagesP. Galya Dimitrova ". Nikolay YankovP. Aneliya Angelova. Stoyan Tanev& James Graham> 0(all100% С8 • Fri 22 May 14:04:33Describe what you are looking for# releases8 226 0• MessagesProject: appC FilesBookmarksM/kan.Today ~J26+10:26:05Tag:View JobGitHub APP1:27 PM4 new commits pushed tomaster byTodorStamatovJiminnycbf9b72b - JY-20955: fix calendar eventduplication checkafe8dceg - Merge branch 'master' into JY-20955-multiple-calendars-events218a8602 - Merge branch 'master' into JY-20955-multiple-calendars-eventsbe560cbf - Merge pull request #12119 fromjiminny/JY-20955-multiple-calendars-eventsjiminny/app | Added by GitHubNewCircleCl APP 1:53 PMDeployment Successful!Project: appWhen:05/22/202610:53:15Tag:View JobMessage #releases+Aa..•...
|
71003
|
NULL
|
NULL
|
NULL
|
|
71006
|
2553
|
0
|
2026-05-22T11:05:03.124454+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447903124_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"bounds":{"left":0.390625,"top":0.2490024,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.40226063,"top":0.2490024,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.4119016,"top":0.24740623,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.4192154,"top":0.24740623,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"bounds":{"left":0.6911569,"top":0.10055866,"width":0.009973404,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.703125,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.7124335,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.72140956,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7287234,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","depth":4,"bounds":{"left":0.4481383,"top":0.09736632,"width":0.36269948,"height":0.90263367},"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5111928977143741995
|
-3204935344002590708
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
71004
|
NULL
|
NULL
|
NULL
|
|
71007
|
2552
|
0
|
2026-05-22T11:05:06.039673+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447906039_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5111928977143741995
|
-3204935344002590708
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
71008
|
2553
|
1
|
2026-05-22T11:05:33.633324+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447933633_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"bounds":{"left":0.390625,"top":0.2490024,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.40226063,"top":0.2490024,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"}]...
|
-1185626629069528695
|
-8204420481329034302
|
idle
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
PhostormFV faVsco.js°9 master kroledey© InsightsService.php© NumberAllocator.php1extmessagingservice.pngc I willoclient.onpcIwlloclientbullder.pnpcIwilloservice.ono•D UserPilot_ WebhookC AbstractService.php© ActivitvProviderFactory.php©) [EMAIL]© ConferenceService.phpC)InsiahtSeatService.oho© InstantMeetingService.php© IntercomService.php© IpapiClient.php(c) Inan Service nhnl© ParticipantShareService.php@ PlanhatService.php© PlaybackService.phpPlaybackVideoOnlyService.php© PlaybookCategoryService.php© PlaylistGeneratorinterface.phpkesolveleamermeonnection.ong© SimpleThrottleService.php@ ClackService.php© SocialAccountService.php© SoftPhoneService.php© TeamDeactivatedService.php© TeamOwnerService.php123 19)c) Teamservice.php© TranscodeParameterResolver.phpc Userservice.onrLocal changesShelfConsole xLog Xenv.local aon@.liminnvDehuaCommandinhn annlConcole/Commanddpho loadina nhn confialg SoftPhoneManager.php app/Component/Twilio/Conference/ConferenceManag© TextMessagingService.php app/Services/TelephonyUnversioned Files 9 filesE.env.nikilocal appE.env.other app© CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/R6 favicon.ico publicEids.txt aprTraw saL querv.sal appC) SimulateWebhooksCommand.oho app/Console/Commands/Crm/HubspotM+ WEBHOOK FILTERING IMPLEMENTATION.md appPatch succoccfullv annlied (18 minutes aao)synerorlannatpnp©PlaybackController.phppnp api.phpC) CreateSmsSentEvent.php(C) PlanhatActivityListener.pho(C)AskAnythingPromptService.php© AutomatedReportsRepository.php(C) AutomatedReportsCommand.phpphp api v2.phpC) RequestGenerateReportJob.pho(C) AutomatedReportResult.php© AutomatedReport.phpclass UserAutomatedReportsController extends ControllerBI4NLAY7а (61pubulc tunccion -_conscrucelprivate readonly AutomatedReportsRepository $automatedReportsRepositoryprivace readonly Aucomareckeporcsservice saucomareakeportsservice.private readonly Apikesponseservice sapikesponseservice,private readonly kesponse sresponse.private readonly PlanhatService $planhatService,{...1PosTlaoi/vilautomated-reports/interest 1 usagepublic function trackInterest(Request Srequest): JsonResponsef...,* othrows AoplicationExceotionG-Taoi/vlautomated-renortsnublic function List(Request Srequest): IsonResnonsef.}DELETE lanilv1/automated-renorts/uuidpublic function delete(Request Srequest, string $uuid): JsonResponsel...}+ → @ Side-by-side viewer ~Do not ianore vHighlight words 13 g ?81aee7aadScontact = nulliCctane = null.Sopportunity = null;/ Setup services.ScrmService = $this->crmProviderRegistry->get(Steam->crm->provider):if (! Suser->isCrmRequiredo){ScrmService->setUser(Suser->team->owner):} else {scrmservice->serusersuser)'=custom.log= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]© TextMessagingService.php X A console [EU]A console [STAGING]stohenamespace Jininny services lelephony>use ...class TextMessaqngServiceorivate ?Team steam = nulu3 usadesorivate ?TwilioClient stwilionlient = nuuupublic function __construct(private readonly ProviderRegistry $providerRegistry,private readonly ActivityService SactivityService,private readonly Webhook SurlGeneratorprivate readonly TwilioClientBuilder $twilioClientBuilder,* Othrows ConfigurationExceptionpublic function setTeam(Team $team): voidsth1s->team = steam:Sthis-›twilioClient = Sthis->twilioClientBuilder->build(Steam):* Athrows \Exceptionoublic function senduser Sfrom. strina Sto. strina Smessage): Messageinstancelcurrent versionScontact = null;Cctano = null.Sopportunity = null;try {ScrmResolver = app(Crm0wnerResolver::class,'team' => $team!'integrationAdmin' => $user'providerSlug' => $team->qetCrmConfiqurationO->qetProviderNameOScrmService = ScrmResolver->prepareCrmService0:} catch (\Throwable Sthrowable) {100% 2. Fri 22 May 14:05:33AskJiminnyReportActivityServiceTest vCascadeInvestigate Foreign Ke© Salestorce Token F122 V1 V1 AVSkip - Console Commands & Admin SyncTnese are aamin-triggered operations where you explicity want aamin/owner context• All app/Console/Commands/Crm/Sync*. php• app/Jobs/Crm/SyncFieldMetadata.php, SyncProfileMetadata.php• app/Services/crm/IntegrationApp/Jobs/*Kecommencation+0 ..Want me to imolement the fallback for the Hiah Priority items (1-4)? These match the same root cause as the Twilio issueand would address "Unknown customer" symptoms across dialer recordings, hyaration joos, and uploaded recordings asAsking question• Which group should l implement CrmownerResolver fallback for?Which aroup should 1 imolement CrmOwnerResolver falllback for?Hich oriority onlv (1-4)High + Medium (1-6)Also include UndateSalesforceAccount listener and ActivitvController onpertunity svneOnlv #1 MatchCrmDataThe most critical iob for activity CRM matching - safest single changeJust review, don't changeDon't make any changes, just keep the review for reference2 differencasW Windsurf Team1-1.UTE.8io 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
71009
|
2552
|
1
|
2026-05-22T11:05:36.484217+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447936484_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"22","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Telephony;\n\nuse Jiminny\\Component\\Activity\\Services\\GetDefaultActivityTypeService;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\ActivityService;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\ProviderRegistry;\nuse Twilio\\Exceptions\\ConfigurationException;\nuse Twilio\\Exceptions\\TwilioException;\nuse Twilio\\Rest\\Api\\V2010\\Account\\MessageInstance;\n\nclass TextMessagingService\n{\n private ?Team $team = null;\n private ?TwilioClient $twilioClient = null;\n\n public function __construct(\n private readonly ProviderRegistry $providerRegistry,\n private readonly ActivityService $activityService,\n private readonly Webhook $urlGenerator,\n private readonly TwilioClientBuilder $twilioClientBuilder,\n ) {\n }\n\n /**\n * @throws ConfigurationException\n */\n public function setTeam(Team $team): void\n {\n $this->team = $team;\n $this->twilioClient = $this->twilioClientBuilder->build($team);\n }\n\n /**\n * @throws \\Exception\n */\n public function send(User $from, string $to, string $message): MessageInstance\n {\n if ($this->team->id !== $from->team_id) {\n throw new \\InvalidArgumentException('Sender does not belong to this team.');\n }\n\n $payload = [\n 'from' => $from->softphone_number,\n 'body' => $message,\n 'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.\n 'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),\n ];\n\n if ($this->team->twilio_messaging_sid !== null) {\n $payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;\n } else {\n $payload['applicationSid'] = $this->team->twilio_sms_sid;\n }\n\n return $this->twilioClient\n ->messages\n ->create($to, $payload);\n }\n\n /**\n * @throws TwilioException\n */\n public function redact(Activity $activity): void\n {\n $this->twilioClient\n ->messages($activity->telephony_provider_id)\n ->delete();\n }\n\n public function buildActivity(\n ?string $messageId,\n string $type,\n User $user,\n string $from,\n string $to,\n string $message,\n ?string $customerId,\n ?string $objectType,\n ?string $countryCode\n ): Activity {\n $lead = null;\n $account = null;\n $contact = null;\n $stage = null;\n $opportunity = null;\n\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n try {\n if ($customerId) {\n // Query the CRM for full details of this customer.\n [$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);\n\n // Prefer the passed country code from Twilio over CRM data.\n if ($countryCode === null && $crmCountryCode) {\n $countryCode = $crmCountryCode;\n }\n } else {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n // Lookup who the message might be to/from based on their phone number.\n $lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;\n [$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(\n $lookup,\n null,\n $user->getId()\n );\n }\n\n if ($opportunity === null) {\n $opportunities = $crmService->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $user->getId()\n );\n\n if (! empty($opportunities)) {\n $opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);\n }\n }\n } catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {\n // If their CRM has become disconnected, we really have no idea who the text customer is.\n $lead = $account = $opportunity = $contact = $stage = null;\n }\n\n if ($countryCode === null) {\n $countryCode = $user->country_code;\n }\n\n if ($type === Activity::TYPE_SMS_OUTBOUND) {\n $to = phone_e164($countryCode, $to);\n\n // Check they are allowed to text this number.\n if ($this->activityService->userCanText($user, $to, $countryCode) === false) {\n throw new \\InvalidArgumentException('Recipient in block list for this user.');\n }\n\n $title = 'Text to ' . phone_national($countryCode, $to);\n $status = Activity::STATUS_QUEUED;\n } else {\n $title = 'Text from ' . phone_national($countryCode, $from);\n $status = Activity::STATUS_RECEIVED;\n }\n\n $category = $this->getActivityType($user, $type);\n\n $activity = $user->activities()->create([\n 'provider' => Activity::PROVIDER_TWILIO,\n 'telephony_provider_id' => $messageId ?? null,\n 'type' => $type,\n 'title' => $title,\n 'description' => $message,\n 'crm_configuration_id' => $team->crm_id,\n 'playbook_category_id' => $category->id ?? null,\n 'lead_id' => $lead->id ?? null,\n 'account_id' => $account->id ?? null,\n 'contact_id' => $contact->id ?? null,\n 'opportunity_id' => $opportunity->id ?? null,\n 'value' => $opportunity ? $opportunity->value : null,\n 'stage_id' => $stage->id ?? null,\n 'status' => $status,\n 'scheduled_start_time' => now(),\n ]);\n\n if (! $activity instanceof Activity) {\n throw new LogicException('Activity model expected');\n }\n\n // Create two participants to store the sender/receiver of the message.\n $userParticipant = $activity->participants()->create([\n 'user_id' => $user->id,\n 'email' => $user->email,\n 'name' => $user->name,\n 'phone_number' => $user->softphone_number,\n ]);\n\n $prospectParticipant = $activity->participants()->create([\n 'lead_id' => $activity->lead_id ?? null,\n 'contact_id' => $activity->contact_id ?? null,\n 'name' => mb_strimwidth($activity->prospect_name, 0, 100),\n 'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,\n ]);\n\n // Refresh the model to fetch participants we just created so they'll be pushed to ES\n $activity->refresh();\n\n // Depending on the message direction, setup the from/to.\n $activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $userParticipant->id\n : $prospectParticipant->id;\n\n $activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND\n ? $prospectParticipant->id\n : $userParticipant->id;\n\n $activity->save();\n\n return $activity;\n }\n\n public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string\n {\n $team = $user->getTeam();\n\n try {\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $user,\n 'providerSlug' => $team->getCrmConfiguration()->getProviderName(),\n ]);\n $crmService = $crmResolver->prepareCrmService();\n } catch (\\Throwable $throwable) {\n $crmService = $this->providerRegistry->get($team->crm->provider);\n if (! $user->isCrmRequired()) {\n $crmService->setUser($team->getOwner());\n } else {\n $crmService->setUser($user);\n }\n }\n\n // Query the CRM for full details of this customer.\n try {\n [, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);\n } catch (\\Exception $ex) {\n \\Sentry::captureException($ex);\n\n return $user->getCountryCode();\n }\n\n // Prefer the passed country code from CRM data to the user.\n if ($countryCode === null) {\n $countryCode = $user->getCountryCode();\n }\n\n return $countryCode;\n }\n\n private function getActivityType(User $user, string $type): ?PlaybookCategory\n {\n $getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);\n\n return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5111928977143741995
|
-3204935344002590708
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
22
1
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Telephony;
use Jiminny\Component\Activity\Services\GetDefaultActivityTypeService;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Activity;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\ActivityService;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\ProviderRegistry;
use Twilio\Exceptions\ConfigurationException;
use Twilio\Exceptions\TwilioException;
use Twilio\Rest\Api\V2010\Account\MessageInstance;
class TextMessagingService
{
private ?Team $team = null;
private ?TwilioClient $twilioClient = null;
public function __construct(
private readonly ProviderRegistry $providerRegistry,
private readonly ActivityService $activityService,
private readonly Webhook $urlGenerator,
private readonly TwilioClientBuilder $twilioClientBuilder,
) {
}
/**
* @throws ConfigurationException
*/
public function setTeam(Team $team): void
{
$this->team = $team;
$this->twilioClient = $this->twilioClientBuilder->build($team);
}
/**
* @throws \Exception
*/
public function send(User $from, string $to, string $message): MessageInstance
{
if ($this->team->id !== $from->team_id) {
throw new \InvalidArgumentException('Sender does not belong to this team.');
}
$payload = [
'from' => $from->softphone_number,
'body' => $message,
'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replace.
'statusCallback' => $this->urlGenerator->route('jiminny.webhook.softphone.sms.event'),
];
if ($this->team->twilio_messaging_sid !== null) {
$payload['messagingServiceSid'] = $this->team->twilio_messaging_sid;
} else {
$payload['applicationSid'] = $this->team->twilio_sms_sid;
}
return $this->twilioClient
->messages
->create($to, $payload);
}
/**
* @throws TwilioException
*/
public function redact(Activity $activity): void
{
$this->twilioClient
->messages($activity->telephony_provider_id)
->delete();
}
public function buildActivity(
?string $messageId,
string $type,
User $user,
string $from,
string $to,
string $message,
?string $customerId,
?string $objectType,
?string $countryCode
): Activity {
$lead = null;
$account = null;
$contact = null;
$stage = null;
$opportunity = null;
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
try {
if ($customerId) {
// Query the CRM for full details of this customer.
[$lead, $account, $opportunity, $contact, $stage, $crmCountryCode] = $crmService->parseRecords($customerId, $objectType);
// Prefer the passed country code from Twilio over CRM data.
if ($countryCode === null && $crmCountryCode) {
$countryCode = $crmCountryCode;
}
} else {
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
// Lookup who the message might be to/from based on their phone number.
$lookup = $type === Activity::TYPE_SMS_INBOUND ? $from : $to;
[$lead, $account, $opportunity, $contact, $stage] = $decorator->matchByPhone(
$lookup,
null,
$user->getId()
);
}
if ($opportunity === null) {
$opportunities = $crmService->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$user->getId()
);
if (! empty($opportunities)) {
$opportunity = $crmService->syncOpportunity($opportunities[0]['crmId']);
}
}
} catch (SocialAccountTokenInvalidException $accountTokenInvalidException) {
// If their CRM has become disconnected, we really have no idea who the text customer is.
$lead = $account = $opportunity = $contact = $stage = null;
}
if ($countryCode === null) {
$countryCode = $user->country_code;
}
if ($type === Activity::TYPE_SMS_OUTBOUND) {
$to = phone_e164($countryCode, $to);
// Check they are allowed to text this number.
if ($this->activityService->userCanText($user, $to, $countryCode) === false) {
throw new \InvalidArgumentException('Recipient in block list for this user.');
}
$title = 'Text to ' . phone_national($countryCode, $to);
$status = Activity::STATUS_QUEUED;
} else {
$title = 'Text from ' . phone_national($countryCode, $from);
$status = Activity::STATUS_RECEIVED;
}
$category = $this->getActivityType($user, $type);
$activity = $user->activities()->create([
'provider' => Activity::PROVIDER_TWILIO,
'telephony_provider_id' => $messageId ?? null,
'type' => $type,
'title' => $title,
'description' => $message,
'crm_configuration_id' => $team->crm_id,
'playbook_category_id' => $category->id ?? null,
'lead_id' => $lead->id ?? null,
'account_id' => $account->id ?? null,
'contact_id' => $contact->id ?? null,
'opportunity_id' => $opportunity->id ?? null,
'value' => $opportunity ? $opportunity->value : null,
'stage_id' => $stage->id ?? null,
'status' => $status,
'scheduled_start_time' => now(),
]);
if (! $activity instanceof Activity) {
throw new LogicException('Activity model expected');
}
// Create two participants to store the sender/receiver of the message.
$userParticipant = $activity->participants()->create([
'user_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
'phone_number' => $user->softphone_number,
]);
$prospectParticipant = $activity->participants()->create([
'lead_id' => $activity->lead_id ?? null,
'contact_id' => $activity->contact_id ?? null,
'name' => mb_strimwidth($activity->prospect_name, 0, 100),
'phone_number' => $type === Activity::TYPE_SMS_OUTBOUND ? $to : $from,
]);
// Refresh the model to fetch participants we just created so they'll be pushed to ES
$activity->refresh();
// Depending on the message direction, setup the from/to.
$activity->from_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $userParticipant->id
: $prospectParticipant->id;
$activity->to_participant_id = $type === Activity::TYPE_SMS_OUTBOUND
? $prospectParticipant->id
: $userParticipant->id;
$activity->save();
return $activity;
}
public function convertCustomerToCountryCode(User $user, string $customerId, ?string $objectType): string
{
$team = $user->getTeam();
try {
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $user,
'providerSlug' => $team->getCrmConfiguration()->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
} catch (\Throwable $throwable) {
$crmService = $this->providerRegistry->get($team->crm->provider);
if (! $user->isCrmRequired()) {
$crmService->setUser($team->getOwner());
} else {
$crmService->setUser($user);
}
}
// Query the CRM for full details of this customer.
try {
[, , , , , $countryCode] = $crmService->parseRecords($customerId, $objectType);
} catch (\Exception $ex) {
\Sentry::captureException($ex);
return $user->getCountryCode();
}
// Prefer the passed country code from CRM data to the user.
if ($countryCode === null) {
$countryCode = $user->getCountryCode();
}
return $countryCode;
}
private function getActivityType(User $user, string $type): ?PlaybookCategory
{
$getDefaultActivityTypeService = app(GetDefaultActivityTypeService::class);
return $getDefaultActivityTypeService->getForUserAndChannel($user, $type);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
71007
|
NULL
|
NULL
|
NULL
|
|
71010
|
2553
|
2
|
2026-05-22T11:05:43.820403+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447943820_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"14","depth":4,"bounds":{"left":0.390625,"top":0.2490024,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.40226063,"top":0.2490024,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.4119016,"top":0.24740623,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.4192154,"top":0.24740623,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\UserAutomatedReports;\n\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Http\\JsonResponse;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Http\\Controllers\\Controller;\nuse Jiminny\\Http\\Responses\\Api\\Response;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\ApiResponseService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSort;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ReportSortDirection;\nuse Jiminny\\Services\\PlanhatService;\nuse Illuminate\\Http\\Request;\nuse Throwable;\n\nclass UserAutomatedReportsController extends Controller\n{\n public const int RESULTS_PER_PAGE = 25;\n\n public const string SORT_COLUMN = 'sort_column';\n\n public const string SORT_DIRECTION = 'sort_direction';\n\n public function __construct(\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly ApiResponseService $apiResponseService,\n private readonly Response $response,\n private readonly PlanhatService $planhatService,\n ) {\n parent::__construct();\n }\n\n public function trackInterest(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n defer(\n fn () => $this->planhatService->track(\n user: $user,\n event: 'automated-reports-track-interest',\n )\n )->always();\n\n return $this->response->withOk();\n }\n\n /**\n * @throws ApplicationException\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n $teamIds = $request->has('team')\n ? (array) $request->get('team')\n : [];\n $reportTypes = $request->has('report_type')\n ? (array) $request->get('report_type')\n : [];\n $name = $request->has('name') ? trim($request->get('name', '')) : null;\n\n try {\n $fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;\n $toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;\n } catch (\\Exception) {\n return $this->response->errorWrongArgs('Invalid date.');\n }\n\n $page = $request->has('page') ? (int) $request->get('page') : 1;\n $sort = ReportSort::tryFrom(\n $request->get(self::SORT_COLUMN, '')\n ) ?? ReportSort::GENERATED_AT;\n $sortDirection = ReportSortDirection::tryFrom(\n strtolower($request->get(self::SORT_DIRECTION, ''))\n ) ?? ReportSortDirection::DESC;\n\n $paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(\n user: $user,\n sort: $sort,\n sortDirection: $sortDirection,\n resultsPerPage: self::RESULTS_PER_PAGE,\n page: $page,\n fromDate: $fromDate,\n toDate: $toDate,\n teamIds: array_map('intval', $teamIds),\n reportTypes: $reportTypes,\n name: $name,\n );\n\n $reportResults = $this->automatedReportsService->transformReportResults(\n $paginatedUserReports->getCollection()\n );\n $team = $user->getTeam();\n $reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(\n shortVersion: true,\n team: $team\n );\n\n $data = $this->apiResponseService->fromPaginatorToArray(\n paginator: $paginatedUserReports,\n data: $reportResults,\n moreMeta: [\n self::SORT_COLUMN => $sort->value,\n self::SORT_DIRECTION => $sortDirection->value,\n ],\n filters: [\n $reportTypeFilter['id'] => $reportTypeFilter,\n ],\n );\n\n return $this->response->withArray($data);\n }\n\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);\n\n if ($result === null) {\n return new JsonResponse(\n data: ['error' => 'Report not found'],\n status: JsonResponse::HTTP_NOT_FOUND\n );\n }\n\n $result->delete();\n\n return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);\n } catch (Throwable $e) {\n return new JsonResponse(\n data: ['error' => 'Failed to delete report result'],\n status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_selected":false,"is_expanded":false}]...
|
-2756535304298618912
|
-2619120939016537587
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
14
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\UserAutomatedReports;
use Illuminate\Support\Carbon;
use Illuminate\Http\JsonResponse;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Http\Controllers\Controller;
use Jiminny\Http\Responses\Api\Response;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\ApiResponseService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSort;
use Jiminny\Services\Kiosk\AutomatedReports\ReportSortDirection;
use Jiminny\Services\PlanhatService;
use Illuminate\Http\Request;
use Throwable;
class UserAutomatedReportsController extends Controller
{
public const int RESULTS_PER_PAGE = 25;
public const string SORT_COLUMN = 'sort_column';
public const string SORT_DIRECTION = 'sort_direction';
public function __construct(
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly AutomatedReportsService $automatedReportsService,
private readonly ApiResponseService $apiResponseService,
private readonly Response $response,
private readonly PlanhatService $planhatService,
) {
parent::__construct();
}
public function trackInterest(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
defer(
fn () => $this->planhatService->track(
user: $user,
event: 'automated-reports-track-interest',
)
)->always();
return $this->response->withOk();
}
/**
* @throws ApplicationException
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
$teamIds = $request->has('team')
? (array) $request->get('team')
: [];
$reportTypes = $request->has('report_type')
? (array) $request->get('report_type')
: [];
$name = $request->has('name') ? trim($request->get('name', '')) : null;
try {
$fromDate = $request->has('from_date') ? Carbon::parse($request->get('from_date')) : null;
$toDate = $request->has('to_date') ? Carbon::parse($request->get('to_date')) : null;
} catch (\Exception) {
return $this->response->errorWrongArgs('Invalid date.');
}
$page = $request->has('page') ? (int) $request->get('page') : 1;
$sort = ReportSort::tryFrom(
$request->get(self::SORT_COLUMN, '')
) ?? ReportSort::GENERATED_AT;
$sortDirection = ReportSortDirection::tryFrom(
strtolower($request->get(self::SORT_DIRECTION, ''))
) ?? ReportSortDirection::DESC;
$paginatedUserReports = $this->automatedReportsRepository->getPaginatedUserReports(
user: $user,
sort: $sort,
sortDirection: $sortDirection,
resultsPerPage: self::RESULTS_PER_PAGE,
page: $page,
fromDate: $fromDate,
toDate: $toDate,
teamIds: array_map('intval', $teamIds),
reportTypes: $reportTypes,
name: $name,
);
$reportResults = $this->automatedReportsService->transformReportResults(
$paginatedUserReports->getCollection()
);
$team = $user->getTeam();
$reportTypeFilter = $this->automatedReportsService->getReportTypeFieldData(
shortVersion: true,
team: $team
);
$data = $this->apiResponseService->fromPaginatorToArray(
paginator: $paginatedUserReports,
data: $reportResults,
moreMeta: [
self::SORT_COLUMN => $sort->value,
self::SORT_DIRECTION => $sortDirection->value,
],
filters: [
$reportTypeFilter['id'] => $reportTypeFilter,
],
);
return $this->response->withArray($data);
}
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$result = $this->automatedReportsRepository->findResultByUuidForUser($uuid, $user);
if ($result === null) {
return new JsonResponse(
data: ['error' => 'Report not found'],
status: JsonResponse::HTTP_NOT_FOUND
);
}
$result->delete();
return new JsonResponse(null, JsonResponse::HTTP_NO_CONTENT);
} catch (Throwable $e) {
return new JsonResponse(
data: ['error' => 'Failed to delete report result'],
status: JsonResponse::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}...
|
71008
|
NULL
|
NULL
|
NULL
|
|
71011
|
2553
|
3
|
2026-05-22T11:05:44.676565+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447944676_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4235983745889776938
|
-8204421443435123770
|
visual_change
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
PhostormcodeFV faVsco.js°9 master kroledey© InsightsService.php© NumberAllocator.php1extmessagingservice.pngc I willoclient.onp© TwilioClientBuilder.phpcIwilloservice.ono© TwilioSubAccountCreator.php•D UserPilotWebhookC AbstractService.php© ActivitvProviderFactory.php©) [EMAIL]© ConferenceService.phpC)InsiahtSeatService.oho© InstantMeetingService.php© IntercomService.php© IpapiClient.php(c) Inan Service nhnl© ParticipantShareService.php@ PlanhatService.php© PlaybackService.phpPlaybackVideoOnlyService.php© PlaybookCategoryService.php© PlaylistGeneratorinterface.php(@) PocolveTeamCrmConnection.ong© SimpleThrottleService.phpslackservice.ono© SocialAccountService.php© SoftPhoneService.phpc) TeamDeactivatedService.php© TeamOwnerService.phpc) Teamservice.php© TranscodeParameterResolver.phpc) Userservice.onr@ Uuid.ohp,D TraitsM UseCases> UserMUtils• M Validationl> OVOphp helners.ohn9 InitialFrontendState.nhn(C).liminnv nhnl© Plan.php© Serializer.php© TeamScimDetails.php)M hoatctran) M huild>C confiaPatch succoccfullv annlied (18 minutes aao)C ActivityController.ong© ConvertLeadActivities.php(C) SaveActivity.pnp© SyncPlanhat.phposynerorlannatonp© AcuvityLeadConvertea.php© UserAutomatedReportsController.php x PlaybackController.phppnp api.phpC) CreateSmsSentEvent.php(C) PlanhatActivityListener.pho(C) AskAnythingPromptService.pho(C) AutomatedReportsRepositorv.php(C) AutomatedReportsCommand.phpphp api v2.phpC) RequestGenerateReportJob.pho(C) AutomatedReportResult.php©AutomatedReport.ohpuse Jiminny Services Kiosk AutomatedRenorts RevortSortDirection:BI4NLAYuse Jiminny \Services\PlanhatService;use Illuminate \Http\Requestuse Throwable:class lserAutomatedRenontsControllen extends Controllenpublic const int RESULTS_PER_PAGE = 25;Z usagespublic const string SORT_COLUMN = 'sort_column';public const string SORT DIRECTION = 'sort direction':30 đpublic tunction constructprivate readonly Automatedkeportsservice sautomatedkeportsserviceprivate readonly AplResponseservice saplResponseservice,rivate readonly response Sresponse.private readonly PlanhatService Splanhatservice,)£...7POSTlaoi/v1/automated-reports/interest 1usagepublic function trackInterest(Request $request): JsonResponse(...}55* Athrows AnnZicationSxcentionGET lanilv1lautomated-renorts589 >public function list(Request Srequest): JsonResponse(...}127119%DELETE /api/v1/automated-reports/{uuid)public function delete(Request Srequest, string $uuid): JsonResponsef...}100% 2• Fri 22 May 14:05:44AskJiminnyReportActivityServiceTest -=custom.log= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]Cascade© TextMessagingService.php X A console [EU]A console [STAGING]Investigate Foreign Ke© Salestorce Token Fa+0 ..stohe122 V1 V1 AVMedium Prioritv - LIstener svnc tlowsnamespace Jininny services lelephony>use ...Updates Salesforce account on team changes. No fallback if admin token invalid.6. ActivityController.php:1176-1187class TextMessaqngServiceSyncs opportunity on activity update. Falls through silentlyLow Priority - Per-user context talllback would be wronc).orivate ?Team steam = nuluTnese rely on the speciic user's permissions in salestorce, talling back to another user could leak data or modiy wrong3 usadesrecordsorivate ?TwilioClient Stwilionlient = nult• ActivityController.php:217-228 - per-user CRM access (already handles exception)• CrmService.php - per-user deal insightspublic function __construct(private readonly ProviderRegistry SproviderRegistry.• OnboardController.php - per-user onboardingprivate readonly ActivityService SactivityService,Skip - Console Commands & Admin Syncprivate readonly TwilioClientBuilder $twilioClientBuilder,These are admin-triggered operations where vou explicitly want admin/owner context• All app/Console/Commands/Crm/Syncx.phr•app/ Jods/crm/ syncrle lometadata. onp, syncrrotz lereradaca. oneapp/Services/Crm/IntegrationApp/Jobs/** Othrows ConfigurationExceptionrecommencarionnublie funation co+Toam(Toam Stoam)• woidlWant me to imolement the fallback for the Hich Prioritv items (1-4)2 These match the same root cause as the Twilio issuernneesroamie roameSthis-›twilioClient = Sthis->twilioClientBuilder->build(Steam):Acking question• Which aroup should I implement CrmOwnerResolver fallback for?* dchrows Exceotzonoublic function sendUser Sfrom. strina Sto. strina Smessage): MessageinstancelWhich aroun should I imnlement CrmOwnerRecolver fallback for?if (Sthis->team->id |== Sfrom->team id) ≤throw new \InvalidArgumentException( message: 'Sender does not belong to this team.');High priority only (1-4)MatchCrmData. HvdrateCrmDataBvExternalCallid, UodateCrmFieldData. CreateActivitvFromUoload - same root cause as.twuilieSnavload =Hich + Medium (1-6)Ifnom' => &from->softnhone numben.Alco include UndateSalesforceAccount listener and Activitycontroller opportunity sync'hody' => Smessade!'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replacOnlv # MatchcrmDataThe most critical job for activity CRM matching - safest single changeIstatusCallhack' = Sthis-sunlGenenaton.>noutedname:tjiminnv.wehhook.softnhone.sms.eventi WebhoolDon't make anv chandes just keen the review for referenceif ($this->team->twilio_messaging_sid !== null) {Spayload[ 'messagingServiceSid'] = Sthis->team->twilio_messaging_sid:} else {<> Code Claude Qnus 1.7 MediumSpayload['applicationSid'] = Sthis->team->twilio_ sms_ sid:W Windsurf Toamio 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
71012
|
2552
|
2
|
2026-05-22T11:05:57.317020+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447957317_m1.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8243381250999052583
|
-8204424741936591934
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
SlackFileEditViewGoHistoryWindowHelpAPP (DOCKER0 81DEV (-zsh)O $82APP (-zsh)tests/Unit/Services/Activity/RingCentral/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/ServiceTest.phptests/Unit/Services/Activity/TwilioVideo/TwilioVideoMetadataHandlerTest.phptests/Unit/Services/Kiosk/AutomatedReports/AutomatedReportsServiceTest.phptests/Unit/Services/Mail/0ffice/EmailApiClientTest.phptests/Unit/Services/Mail/TextRelayServiceTest.phptests/Unit/Services/RecallAI/RecallAIServiceTest.php79 files changed, 4254 insertions(+), 2020 deletions(-)create mode 100644 .github/claude-reviewer/no-ticket-warning.txtcreate mode 100644.github/claude-reviewer/scripts/fetch-jira-context.mjsdelete mode 100644 app/Component/ES/Processor/BatchStatusInterface.phpcreatemode 100644 app/Component/ES/Processor/RedisEntityExtractor.phpdeletemode100644 app/Component/ES/Processor/Traits/WorkerIdTrait.phpcreate mode 100644 app/Component/ES/QueuePriorityEnum.phpTrginusWorker/aTrai+: Phpcreate mode 100644 front-end/src/components/DealInsights/Modals/__tests__/AskAnythingModacreate mode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Asdeletemode100644 front-end/src/components/shared/AskAnything/__tests__/__snapshots__/Ascreatemode 100644 tests/Unit/Component/ES/Processor/RedisEntityExtractorTest.phpdelete mode 100644 tests/Unit/Component/ES/Processor/Traits/WorkerIdTraitTest.phpcreate mode 100644 tests/Unit/Component/ES/QueuePriorityEnumTest.phpcreate mode 100644 tests/Unit/Notifications/Activities/SmsReceivedTest.phpcreate mode 100644 tests/Unit/Services/Mail/TextRelayServiceTest.phplukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20963-fix-imporSwitched to a new branch 'JY-20963-fix-import-on-deleted-entity'lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20963-fix-import-on-deleted-entdocker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn moreat [URL_WITH_CREDENTIALS] (JY-20963-fix-import-on-deleted-ent|docker exec -it docker_lamp_1./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.phPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.PHPruntime: 8.3.30Running analysis on 7 cores with 10 files perprocess.Parallel runner is an experimental feature and may be unstable, use itat your ownrisk.Loaded config default from".php-cs-fixer.dist.php"5691/5691100%Fixed 0 of 5691 files in 96.077 seconds, 67.00 MBmemory used•HomeDMsActivityFilesLater+ED→Jiminny ...& jiminny-x-integrati...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# happy_birthday# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messagesP. Galya Dimitrova ". Nikolay YankovP. Aneliya Angelova. Stoyan Tanev& James Graham> 0(all100% С8 • Fri 22 May 14:05:57Describe what you are looking for# releases8 226 0• MessagesProject: appC FilesBookmarksM/kan.Today ~J26+10:26:05Tag:View JobGitHub APP1:27 PM4 new commits pushed tomaster byTodorStamatovJiminnycbf9b72b - JY-20955: fix calendar eventduplication checkafe8dceg - Merge branch 'master' into JY-20955-multiple-calendars-events218a8602 - Merge branch 'master' into JY-20955-multiple-calendars-eventsbe560cbf - Merge pull request #12119 fromjiminny/JY-20955-multiple-calendars-eventsjiminny/app | Added by GitHubNewCircleCl APP 1:53 PMDeployment Successful!Project: appWhen:05/22/202610:53:15Tag:View JobMessage #releases+Aa..•...
|
71007
|
NULL
|
NULL
|
NULL
|
|
71013
|
2553
|
4
|
2026-05-22T11:05:57.426108+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-22/1779 /Users/lukas/.screenpipe/data/data/2026-05-22/1779447957426_m2.jpg...
|
PhpStorm
|
faVsco.js – TextMessagingService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4047408223668449518
|
-8636777727364969024
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
PhostormcodeFV faVsco.js°9 master kroledey© InsightsService.php© NumberAllocator.php1extmessagingservice.pngc I willoclient.onp© TwilioClientBuilder.phpcIwilloservice.ono© TwilioSubAccountCreator.php•D UserPilotWebhookC AbstractService.php© ActivitvProviderFactory.php©) [EMAIL]© ConferenceService.phpC)InsiahtSeatService.oho© InstantMeetingService.php© IntercomService.php© IpapiClient.php(c) Inan Service nhn© ParticipantShareService.php@ PlanhatService.php© PlaybackService.phpPlaybackVideoOnlyService.php© PlaybookCategoryService.php© PlaylistGeneratorinterface.php(@) PocolveTeamCrmConnection.ong© SimpleThrottleService.phpslackservice.ono© SocialAccountService.php© SoftPhoneService.phpc) TeamDeactivatedService.php© TeamOwnerService.phpc) Teamservice.php© TranscodeParameterResolver.phpc) Userservice.one@ Uuid.ohp,D TraitsM UseCases> UserMUtils• M Validationl> OVOphp helners.ohn9 InitialFrontendState.nhn(C).liminnv nhnl© Plan.php© Serializer.php© TeamScimDetails.php)M hoatctran) M huild>C confiaPatch succoccfullv annlied (18 minutes aao)C ActivityController.ong© ConvertLeadActivities.php(C) SaveActivity.pnp© SyncPlanhat.phposynerorlannatonp© AcuvityLeadConvertea.php© UserAutomatedReportsController.php x PlaybackController.phppnp api.phpC) CreateSmsSentEvent.php(C) PlanhatActivityListener.pho(C) AskAnythingPromptService.pho(C) AutomatedReportsRepositorv.php(C) AutomatedReportsCommand.phpphp api v2.phpC) RequestGenerateReportJob.pho(C) AutomatedReportResult.php©AutomatedReport.phpuse Jiminny Services Kiosk AutomatedRenorts RevortSortDirection:BI4NLAYuse Jiminny Services PlanhatService:use Illuminate\Http\Requestuse Throwable:class lserAutomatedRenontsControllen extends Controllenpublic const int RESULTS_PER_PAGE = 25;Z usagespublic const string SORT_COLUMN = 'sort_column';public const string SORT DIRECTION = 'sort direction':30 đpublic tunction constructprivate readonly Automatedkeportsservice sautomatedkeportsserviceprivate readonly AplResponseservice saplResponseservice,rivate readonly response Sresponse.private readonly PlanhatService Splanhatservice,)£...7POSTlaoi/v1/automated-reports/interest 1usagepublic function trackInterest(Request $request): JsonResponse(...}* Athrows AnnlicationSxcentionGET lanilv1lautomated-renortsSANOSpublic function list(Request Srequest): JsonResponse(...}127119%DELETE /api/v1/automated-reports/{uuid)public function delete(Request Srequest, string Suuid): JsonResponse(...}=custom.log= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]© TextMessagingService.php X A console (EU]A console [STAGING]stohenamespace Jininny services lelephony>use ...class TextMessaqngService3 usadesorivate ?TwilioClient stwilionlient = nuuupublic function __construct(private readonly ProviderRegistry SproviderRegistry.private readonly ActivityService SactivityService,private readonly TwilioClientBuilder $twilioClientBuilder,& console [PROD]122 V1 V1 AV* Othrows ConfigurationExceptionnublie funation co+Toam(Toam Stoam)• woidlrnncesroamie roameSthis-›twilioClient = Sthis->twilioClientBuilder->build(Steam):* dchrows Exceotzonoublic function senduser Sfrom. strina Sto. strina Smessage): Messageinstancelif (Sthis->team->id |== Sfrom->team id) {throw new \InvalidArgumentException( message: 'Sender does not belong to this team.');Snavload =Ifnom' => &from->softnhone numben.'hody' => Smessade!'smartEncoded' => true, // Detect Unicode characters that have a similar GSM-7 character and replacIstatusCallhack' = Sthis-sunlGenenaton.>noutedname:tjiminnv.wehhook.softnhone.sms.eventi Webhoolif ($this->team->twilio_messaging_sid !== null) {Spayload[ 'messagingServiceSid'] = Sthis->team->twilio_messaging_sid:}else {Spayload['applicationSid'] = Sthis->team->twilio sms sid:100% 52• Fri 22 May 14:05:57AskJiminnyReportActivityServiceTest vCascadeInvestigate Foreign Ke© Salestorce Token Fa+0 ..• Let existing outer catch blocks handle any Socia Account TokenInva lidException ov settina eRM data to nullThis ensures Twilio calls will use another active Salesforce token when the admin token expires, preventing "Unknown® al **Review all olaces in the code where we could use crmownerReso ver to make sure that service works even in the casetnere is no token valleSearched crmProviderRecistrv->aet.oroviderReaistrv->oet.crml ProviderReaistrv.->aet in apo (78)Poad MatchCrmData nhrThougnt for 2sReview: Places Using CRM Service Without FallbackI've reviewed the codebase. Here's a categorized list of places where crmService->setUser() is called directly that wouldbenefit from CrmlwnerRecolver to handle invalid tokens.High Priority - Runtime Customer Matching (same root cause as Twilio issue)apo/.lobs/Activitvilmport/MatchCrmData.ohn irtace "Unknown customer" or fall silently when admin token exoires:1.MatchCrmData.oho: 178-189Critical: Ioh that matches CRM data for activities (dialer calls etc.). Currentlv uses onlv tean_saeth-ner!)). If owner token2.HvdrateCrmDataBvExternalCallIdJob.oho:69Hydrates CRM data by external call ID. Uses only team->getOwner() .3. UpdatecrmF1elddataJob.php:265-268Uodates CRM field data on activities. Uses onlv tean->aeto-nero .4.CreateActivitvFromUnloadService.nho:111-114Parses CRM records for uploaded recordings. Uses only team->getOwner() .Which aroun should I imnlement CrmOwnerRecolver fallback for?High priority only (1-4)MatchCrmData. HvdrateCrmDataBvExternalCallid, UodateCrmFieldData. CreateActivitvFromUoload - same root cause as.twuilieHich + Medium (1-6)Alco include UndateSalesforceAccount listener and Activitycontroller opportunity syncOnlv # MatchcrmDataThe most critical job for activity CRM matching - safest single changeDon't make anv chandes iust keen the review for reference<> Code Claude Qnus 4.7 MediumW Windsurf Team1-1.UTE.8io 4 space:...
|
71011
|
NULL
|
NULL
|
NULL
|
|
33615
|
1277
|
17
|
2026-05-13T10:36:14.868855+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668574868_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelay.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
19
3
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Models;
use Jiminny\Component\Eloquent\Builder;
use Jiminny\Traits\Enums;
use Jiminny\Traits\RequiresUUID;
/**
* Jiminny\Models\TextRelay
*
* @property int $id
* @property mixed|null $uuid
* @property string $email_provider
* @property string $email_provider_id
* @property \Illuminate\Support\Carbon|null $email_sent_at
* @property string|null $sender
* @property string|null $recipient
* @property string $status
* @property int|null $code
* @property int|null $origin_activity_id
* @property int|null $activity_id
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \Jiminny\Models\Activity|null $activity
* @property-read string $id_string
* @property-read \Jiminny\Models\Activity|null $originActivity
*
* @method static Builder|TextRelay chunkByIdDesc($count, callable $callback, $column = null, $alias = null)
* @method static Builder|TextRelay idOrUuId($idOrUuid, bool $first = true)
* @method static Builder|TextRelay newModelQuery()
* @method static Builder|TextRelay newQuery()
* @method static Builder|TextRelay query()
* @method static Builder|TextRelay uuid(string $uuid, bool $first = true)
* @method static Builder|TextRelay whereActivityId($value)
* @method static Builder|TextRelay whereCode($value)
* @method static Builder|TextRelay whereCreatedAt($value)
* @method static Builder|TextRelay whereEmailProvider($value)
* @method static Builder|TextRelay whereEmailProviderId($value)
* @method static Builder|TextRelay whereEmailSentAt($value)
* @method static Builder|TextRelay whereId($value)
* @method static Builder|TextRelay whereOriginActivityId($value)
* @method static Builder|TextRelay whereRecipient($value)
* @method static Builder|TextRelay whereSender($value)
* @method static Builder|TextRelay whereStatus($value)
* @method static Builder|TextRelay whereUpdatedAt($value)
* @method static Builder|TextRelay whereUuid($value)
*
* @mixin \Eloquent
*/
class TextRelay extends Model
{
use Enums;
use RequiresUUID;
public const STATUS_PROCESSING = 'processing';
public const STATUS_FAILED = 'failed';
public const STATUS_PROCESSED = 'processed';
public const PROVIDER_GSUITE = 'gsuite';
protected $enumStatuses = [
self::STATUS_PROCESSING,
self::STATUS_FAILED,
self::STATUS_PROCESSED,
];
protected $enumProviders = [
self::PROVIDER_GSUITE,
];
protected $table = 'text_relays';
protected $fillable = [
'email_provider',
'email_provider_id',
'email_sent_at',
'sender',
'recipient',
'origin_activity_id',
'activity_id',
'status',
'code',
];
protected $appends = [
'id_string',
];
protected $hidden = [
'uuid',
'id',
];
protected function casts(): array
{
return [
'email_sent_at' => 'datetime',
];
}
/**
* The original (inbound) activity.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo|Activity
*/
public function originActivity()
{
return $this->belongsTo(Activity::class);
}
/**
* The (outbound) activity created by this email relay.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo|Activity
*/
public function activity()
{
return $this->belongsTo(Activity::class);
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.3723404,"top":0.10055866,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.38397607,"top":0.10055866,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39361703,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.40093085,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Models;\n\nuse Jiminny\\Component\\Eloquent\\Builder;\nuse Jiminny\\Traits\\Enums;\nuse Jiminny\\Traits\\RequiresUUID;\n\n/**\n * Jiminny\\Models\\TextRelay\n *\n * @property int $id\n * @property mixed|null $uuid\n * @property string $email_provider\n * @property string $email_provider_id\n * @property \\Illuminate\\Support\\Carbon|null $email_sent_at\n * @property string|null $sender\n * @property string|null $recipient\n * @property string $status\n * @property int|null $code\n * @property int|null $origin_activity_id\n * @property int|null $activity_id\n * @property \\Illuminate\\Support\\Carbon|null $created_at\n * @property \\Illuminate\\Support\\Carbon|null $updated_at\n * @property-read \\Jiminny\\Models\\Activity|null $activity\n * @property-read string $id_string\n * @property-read \\Jiminny\\Models\\Activity|null $originActivity\n *\n * @method static Builder|TextRelay chunkByIdDesc($count, callable $callback, $column = null, $alias = null)\n * @method static Builder|TextRelay idOrUuId($idOrUuid, bool $first = true)\n * @method static Builder|TextRelay newModelQuery()\n * @method static Builder|TextRelay newQuery()\n * @method static Builder|TextRelay query()\n * @method static Builder|TextRelay uuid(string $uuid, bool $first = true)\n * @method static Builder|TextRelay whereActivityId($value)\n * @method static Builder|TextRelay whereCode($value)\n * @method static Builder|TextRelay whereCreatedAt($value)\n * @method static Builder|TextRelay whereEmailProvider($value)\n * @method static Builder|TextRelay whereEmailProviderId($value)\n * @method static Builder|TextRelay whereEmailSentAt($value)\n * @method static Builder|TextRelay whereId($value)\n * @method static Builder|TextRelay whereOriginActivityId($value)\n * @method static Builder|TextRelay whereRecipient($value)\n * @method static Builder|TextRelay whereSender($value)\n * @method static Builder|TextRelay whereStatus($value)\n * @method static Builder|TextRelay whereUpdatedAt($value)\n * @method static Builder|TextRelay whereUuid($value)\n *\n * @mixin \\Eloquent\n */\nclass TextRelay extends Model\n{\n use Enums;\n use RequiresUUID;\n\n public const STATUS_PROCESSING = 'processing';\n public const STATUS_FAILED = 'failed';\n public const STATUS_PROCESSED = 'processed';\n\n public const PROVIDER_GSUITE = 'gsuite';\n\n\n protected $enumStatuses = [\n self::STATUS_PROCESSING,\n self::STATUS_FAILED,\n self::STATUS_PROCESSED,\n ];\n\n protected $enumProviders = [\n self::PROVIDER_GSUITE,\n ];\n\n protected $table = 'text_relays';\n\n protected $fillable = [\n 'email_provider',\n 'email_provider_id',\n 'email_sent_at',\n 'sender',\n 'recipient',\n 'origin_activity_id',\n 'activity_id',\n 'status',\n 'code',\n ];\n\n protected $appends = [\n 'id_string',\n ];\n\n protected $hidden = [\n 'uuid',\n 'id',\n ];\n\n protected function casts(): array\n {\n return [\n 'email_sent_at' => 'datetime',\n ];\n }\n\n /**\n * The original (inbound) activity.\n *\n * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsTo|Activity\n */\n public function originActivity()\n {\n return $this->belongsTo(Activity::class);\n }\n\n /**\n * The (outbound) activity created by this email relay.\n *\n * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsTo|Activity\n */\n public function activity()\n {\n return $this->belongsTo(Activity::class);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Models;\n\nuse Jiminny\\Component\\Eloquent\\Builder;\nuse Jiminny\\Traits\\Enums;\nuse Jiminny\\Traits\\RequiresUUID;\n\n/**\n * Jiminny\\Models\\TextRelay\n *\n * @property int $id\n * @property mixed|null $uuid\n * @property string $email_provider\n * @property string $email_provider_id\n * @property \\Illuminate\\Support\\Carbon|null $email_sent_at\n * @property string|null $sender\n * @property string|null $recipient\n * @property string $status\n * @property int|null $code\n * @property int|null $origin_activity_id\n * @property int|null $activity_id\n * @property \\Illuminate\\Support\\Carbon|null $created_at\n * @property \\Illuminate\\Support\\Carbon|null $updated_at\n * @property-read \\Jiminny\\Models\\Activity|null $activity\n * @property-read string $id_string\n * @property-read \\Jiminny\\Models\\Activity|null $originActivity\n *\n * @method static Builder|TextRelay chunkByIdDesc($count, callable $callback, $column = null, $alias = null)\n * @method static Builder|TextRelay idOrUuId($idOrUuid, bool $first = true)\n * @method static Builder|TextRelay newModelQuery()\n * @method static Builder|TextRelay newQuery()\n * @method static Builder|TextRelay query()\n * @method static Builder|TextRelay uuid(string $uuid, bool $first = true)\n * @method static Builder|TextRelay whereActivityId($value)\n * @method static Builder|TextRelay whereCode($value)\n * @method static Builder|TextRelay whereCreatedAt($value)\n * @method static Builder|TextRelay whereEmailProvider($value)\n * @method static Builder|TextRelay whereEmailProviderId($value)\n * @method static Builder|TextRelay whereEmailSentAt($value)\n * @method static Builder|TextRelay whereId($value)\n * @method static Builder|TextRelay whereOriginActivityId($value)\n * @method static Builder|TextRelay whereRecipient($value)\n * @method static Builder|TextRelay whereSender($value)\n * @method static Builder|TextRelay whereStatus($value)\n * @method static Builder|TextRelay whereUpdatedAt($value)\n * @method static Builder|TextRelay whereUuid($value)\n *\n * @mixin \\Eloquent\n */\nclass TextRelay extends Model\n{\n use Enums;\n use RequiresUUID;\n\n public const STATUS_PROCESSING = 'processing';\n public const STATUS_FAILED = 'failed';\n public const STATUS_PROCESSED = 'processed';\n\n public const PROVIDER_GSUITE = 'gsuite';\n\n\n protected $enumStatuses = [\n self::STATUS_PROCESSING,\n self::STATUS_FAILED,\n self::STATUS_PROCESSED,\n ];\n\n protected $enumProviders = [\n self::PROVIDER_GSUITE,\n ];\n\n protected $table = 'text_relays';\n\n protected $fillable = [\n 'email_provider',\n 'email_provider_id',\n 'email_sent_at',\n 'sender',\n 'recipient',\n 'origin_activity_id',\n 'activity_id',\n 'status',\n 'code',\n ];\n\n protected $appends = [\n 'id_string',\n ];\n\n protected $hidden = [\n 'uuid',\n 'id',\n ];\n\n protected function casts(): array\n {\n return [\n 'email_sent_at' => 'datetime',\n ];\n }\n\n /**\n * The original (inbound) activity.\n *\n * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsTo|Activity\n */\n public function originActivity()\n {\n return $this->belongsTo(Activity::class);\n }\n\n /**\n * The (outbound) activity created by this email relay.\n *\n * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsTo|Activity\n */\n public function activity()\n {\n return $this->belongsTo(Activity::class);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.40957448,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"bounds":{"left":0.41821808,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"bounds":{"left":0.42918882,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"bounds":{"left":0.43783244,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"bounds":{"left":0.44647607,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"bounds":{"left":0.4574468,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.46841756,"top":0.09896249,"width":0.024268618,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.4950133,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.50598407,"top":0.09896249,"width":0.029587766,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.7084442,"top":0.09896249,"width":0.02825798,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3973236040361978263
|
-994290614999107944
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
19
3
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Models;
use Jiminny\Component\Eloquent\Builder;
use Jiminny\Traits\Enums;
use Jiminny\Traits\RequiresUUID;
/**
* Jiminny\Models\TextRelay
*
* @property int $id
* @property mixed|null $uuid
* @property string $email_provider
* @property string $email_provider_id
* @property \Illuminate\Support\Carbon|null $email_sent_at
* @property string|null $sender
* @property string|null $recipient
* @property string $status
* @property int|null $code
* @property int|null $origin_activity_id
* @property int|null $activity_id
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \Jiminny\Models\Activity|null $activity
* @property-read string $id_string
* @property-read \Jiminny\Models\Activity|null $originActivity
*
* @method static Builder|TextRelay chunkByIdDesc($count, callable $callback, $column = null, $alias = null)
* @method static Builder|TextRelay idOrUuId($idOrUuid, bool $first = true)
* @method static Builder|TextRelay newModelQuery()
* @method static Builder|TextRelay newQuery()
* @method static Builder|TextRelay query()
* @method static Builder|TextRelay uuid(string $uuid, bool $first = true)
* @method static Builder|TextRelay whereActivityId($value)
* @method static Builder|TextRelay whereCode($value)
* @method static Builder|TextRelay whereCreatedAt($value)
* @method static Builder|TextRelay whereEmailProvider($value)
* @method static Builder|TextRelay whereEmailProviderId($value)
* @method static Builder|TextRelay whereEmailSentAt($value)
* @method static Builder|TextRelay whereId($value)
* @method static Builder|TextRelay whereOriginActivityId($value)
* @method static Builder|TextRelay whereRecipient($value)
* @method static Builder|TextRelay whereSender($value)
* @method static Builder|TextRelay whereStatus($value)
* @method static Builder|TextRelay whereUpdatedAt($value)
* @method static Builder|TextRelay whereUuid($value)
*
* @mixin \Eloquent
*/
class TextRelay extends Model
{
use Enums;
use RequiresUUID;
public const STATUS_PROCESSING = 'processing';
public const STATUS_FAILED = 'failed';
public const STATUS_PROCESSED = 'processed';
public const PROVIDER_GSUITE = 'gsuite';
protected $enumStatuses = [
self::STATUS_PROCESSING,
self::STATUS_FAILED,
self::STATUS_PROCESSED,
];
protected $enumProviders = [
self::PROVIDER_GSUITE,
];
protected $table = 'text_relays';
protected $fillable = [
'email_provider',
'email_provider_id',
'email_sent_at',
'sender',
'recipient',
'origin_activity_id',
'activity_id',
'status',
'code',
];
protected $appends = [
'id_string',
];
protected $hidden = [
'uuid',
'id',
];
protected function casts(): array
{
return [
'email_sent_at' => 'datetime',
];
}
/**
* The original (inbound) activity.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo|Activity
*/
public function originActivity()
{
return $this->belongsTo(Activity::class);
}
/**
* The (outbound) activity created by this email relay.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo|Activity
*/
public function activity()
{
return $this->belongsTo(Activity::class);
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
33616
|
1276
|
24
|
2026-05-13T10:36:14.868821+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668574868_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelay.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
19
3...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"}]...
|
5123515916744811362
|
-8204424879375537216
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
19
3
QuickTime PlayerFileEditViewWindowHelpGalya Dimitrova (Presenting, annotating)SlackFileEditViewGoHistoryWindowHelp÷# Plattor88JIMg For you• Recent [# Starred° Apps|& Plans0 SpacesStarredJiminny (New)| u Platform TelIID ProcessingUID SE KanbanIID Capture TeaU Enterprise 9Discovery+ActivityFiesLaterMoreProductRecent(9 Service-Desk= More spacesE FiltersB DashboardsOperations& CustomersJiminny Inc~+ More unread messagesE Lukas Kovalik, Nikolay..C. Nikolay IvanovP. Nikolay Yankov. Petko Kashinski. Stefka Stoyanovad Stoyan Tanev. Vasil Vasilev E#. Vilma AC. ZoriAP. Galya Dimitrova...Channels# alertsApps2 ConfluenceGoogle CalendarGoogle DrivejiminnyJira CloudToastu UserpilotQ Describe what you are looking for# alerts8 22| MessagesAdd canvasO Filesmyana neeseva 1uzyhas been added to #alerts by Mira.Monday, 6 April -Thursday. 9 AprilAutomation for Jira APPSRD-6782 Transcription issue has been escalated with Critical priority to" @hereAutomation for Jira APPSRD:6782 Transcription issue has been assigned with Critical priority to Mihail Mihaylov @hereToday ~CircleCI APP 10:122 PRs with vulnerability fixes are ready for review $Please take a look at the code and confirm that everything works properly on your local machine oron a planet environment j)Pull requests (Gjiminny/app)• $11970 fix/securityl.composer dependensyundates - 2026-04-15 (secfix/composer-20260415)• $11969 fix/securitvl.nom denendensy_undates - 2026-04-15 (secfix/npm-20260415 )|View workflow.rvn$ 1=|= «Message #alertsAa@JY-19967 Upgrade Python and libraries - AprMAINTENANCEBACKLOG V+ Createmeet.9o09e.com is snaring your SercenStop sharingClick or hold page_up + page_down to start dictating(alol# Support Daily - in 1h 24 m100% C8• Wed 13 May 13:36:1490008• Wed 15 Apr 10:37Campus X|) FirebaseE UM EvalunAsk Rovo4ComponentsMore 9+4.5= 8== 8= &= &= *= 8= 8= 8= %= 8=Nikolay NikolovGalya Dimitrova4 othersStefka StoyanovaLukas Kovalik10:37 AM | [Platform] Planning | Session i7...
|
33613
|
NULL
|
NULL
|
NULL
|
|
35154
|
1315
|
11
|
2026-05-13T12:15:26.794748+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778674526794_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelay.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Firefox FileEditViewHistoryBookmarksToolsWindowHel Firefox FileEditViewHistoryBookmarksToolsWindowHelp• 0APPapp/Console/Commands/Activities/SetupIntegration/TwilioSetS3RecordingCredentialsCommand.bapp/Console/Kernel.phpapp/Jobs/ImportRemoteTrackJob.phpapp/Services/Activity/Twilio/S3RecordingCredentialsService.phptests/Feature/Jobs/ImportRemoteTrackJobTest.phptests/Unit/Component/Encoding/Job/AnalyzeTrackChannelsJobTest.phptests/Unit/Component/FFMpeg/Services/GetSpeechIntervalsTest.phptests/Unit/Services/Activity/Twilio/S3RecordingCredentialsServiceTest.php10 files changed, 823 insertions(+), 23 deletions(-)create mode 100644 app/Console/Commands/Activities/SetupIntegration/TwilioSetS3Recordingcreate mode 100644 app/Services/Activity/Twilio/S3RecordingCredentialsService.phpcreate mode 100644 tests/Unit/Services/Activity/Twilio/S3RecordingCredentialsServiceTestlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20891-improve-;Switched to a new branch 'JY-20891-improve-sms-text-relays'lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20891-improve-sms-text-relays)docker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.plPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminskicontributors.Running analysis on 7 cores with 10 files per process.Parallel runner is an experimental feature and may be unstable, use it at your own risk.Loaded configdefault from-php-cs-fixer.dist.php"5665/5665100%1) app/Jobs/Mailbox/EmailTextRelay.php (no_unused_imports)begin diff/home/jiminny/app/Jobs/Mailbox/EmailTextRelay.php+++/home/jiminny/app/Jobs/Mailbox/EmailTextRelay.php-16,7 +16,6 @@use Jiminny\Mail\Activities|SmsRelayFailed;use Jiminny\Models\Activity;use Jiminny Models \TextRelay;Jiminny\Models\User;useJiminny\Repositories\UserRepository;use Jiminny\Rules\SmsMessage;use Jiminny\Services\Mail\TextRelayService;end diffFixed 1 of 5665 files in 52.535 seconds, 67.00 MBmemory usedWhat's next:Try Docker Debug for seamless, persistent debugging tools in any containeror image →Learn more at https://docs.docker.com/go/debug-cli/lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20891-improve-sms-text-relays)HomeDMsActivityFilesLater..•MorelallJiminny ...# contusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Direct messages. Nikolay Ivanovd. James GrahamStoyan Tanev®. Galya Dimitrova ORe Steliyan Georgiev&. Petko Kashinskie. Aneliya Angelova8. Stefka StoyanovaB. Vasil VasilevLukas Kovalik y...i: AppsToastJira CloudConala CalaSprint Review - in 45 m100% <78•Wed 13 May 15:15:26Describe what you are looking for# releases8 226 0MessagesC FilesBookmarks+3 new messagesNewCircleCI AP.-Deployment Successful!Project: appWhen:05/13/202611:57:10Tag:View JobGitHub APP3:10 PM6 new commits pushed to master by Vasil-Jiminny851bf1a7 - Remove ignored records that causelocal phpstan errors. No functional changes.d08f0260 - Merge branch 'master' intoremove-phpstan-errorsb2d676c3 - Merge branch 'master' intoremove-phpstan-errors1ff6f70f - Merge branch 'master' intoremove-phpstan-errors62a7fe62 - Merge branch 'master' intoremove-phpstan-errorsShow morejiminny/app Added by GitHubVasil Vasilev 3:11 PMStopped. The PR is internal dev optimisation, noneed to reach prod.Message #releases+..•...
|
NULL
|
-4509238414457679012
|
NULL
|
click
|
ocr
|
NULL
|
Firefox FileEditViewHistoryBookmarksToolsWindowHel Firefox FileEditViewHistoryBookmarksToolsWindowHelp• 0APPapp/Console/Commands/Activities/SetupIntegration/TwilioSetS3RecordingCredentialsCommand.bapp/Console/Kernel.phpapp/Jobs/ImportRemoteTrackJob.phpapp/Services/Activity/Twilio/S3RecordingCredentialsService.phptests/Feature/Jobs/ImportRemoteTrackJobTest.phptests/Unit/Component/Encoding/Job/AnalyzeTrackChannelsJobTest.phptests/Unit/Component/FFMpeg/Services/GetSpeechIntervalsTest.phptests/Unit/Services/Activity/Twilio/S3RecordingCredentialsServiceTest.php10 files changed, 823 insertions(+), 23 deletions(-)create mode 100644 app/Console/Commands/Activities/SetupIntegration/TwilioSetS3Recordingcreate mode 100644 app/Services/Activity/Twilio/S3RecordingCredentialsService.phpcreate mode 100644 tests/Unit/Services/Activity/Twilio/S3RecordingCredentialsServiceTestlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co -b JY-20891-improve-;Switched to a new branch 'JY-20891-improve-sms-text-relays'lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20891-improve-sms-text-relays)docker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.plPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminskicontributors.Running analysis on 7 cores with 10 files per process.Parallel runner is an experimental feature and may be unstable, use it at your own risk.Loaded configdefault from-php-cs-fixer.dist.php"5665/5665100%1) app/Jobs/Mailbox/EmailTextRelay.php (no_unused_imports)begin diff/home/jiminny/app/Jobs/Mailbox/EmailTextRelay.php+++/home/jiminny/app/Jobs/Mailbox/EmailTextRelay.php-16,7 +16,6 @@use Jiminny\Mail\Activities|SmsRelayFailed;use Jiminny\Models\Activity;use Jiminny Models \TextRelay;Jiminny\Models\User;useJiminny\Repositories\UserRepository;use Jiminny\Rules\SmsMessage;use Jiminny\Services\Mail\TextRelayService;end diffFixed 1 of 5665 files in 52.535 seconds, 67.00 MBmemory usedWhat's next:Try Docker Debug for seamless, persistent debugging tools in any containeror image →Learn more at https://docs.docker.com/go/debug-cli/lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20891-improve-sms-text-relays)HomeDMsActivityFilesLater..•MorelallJiminny ...# contusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Direct messages. Nikolay Ivanovd. James GrahamStoyan Tanev®. Galya Dimitrova ORe Steliyan Georgiev&. Petko Kashinskie. Aneliya Angelova8. Stefka StoyanovaB. Vasil VasilevLukas Kovalik y...i: AppsToastJira CloudConala CalaSprint Review - in 45 m100% <78•Wed 13 May 15:15:26Describe what you are looking for# releases8 226 0MessagesC FilesBookmarks+3 new messagesNewCircleCI AP.-Deployment Successful!Project: appWhen:05/13/202611:57:10Tag:View JobGitHub APP3:10 PM6 new commits pushed to master by Vasil-Jiminny851bf1a7 - Remove ignored records that causelocal phpstan errors. No functional changes.d08f0260 - Merge branch 'master' intoremove-phpstan-errorsb2d676c3 - Merge branch 'master' intoremove-phpstan-errors1ff6f70f - Merge branch 'master' intoremove-phpstan-errors62a7fe62 - Merge branch 'master' intoremove-phpstan-errorsShow morejiminny/app Added by GitHubVasil Vasilev 3:11 PMStopped. The PR is internal dev optimisation, noneed to reach prod.Message #releases+..•...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
35155
|
1316
|
12
|
2026-05-13T12:15:26.794752+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778674526794_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelay.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhpStormEV favsco.jsProjectVIewINavigarecodeLarave PhpStormEV favsco.jsProjectVIewINavigarecodeLaravelg9 JY-20891-improve-sms-text-relaysRefactorloOlWindow©ActivityCommentRepositc©ActivityLogRepository-phy© ActivityMessageRepositol©ActivityMomentRepositor©Textmessagingservice.phg© ActivityProviderRepositor©ActivityRepository.php© ActivitySearchFilterReposActivityShareRepository.-F51@sclass |TextRelay extends Model© ActivityUploadSettingRep©AiPromptRepository.php53@AskAnythingRepository.pl54use Enums:use RequiresUUID;(c) Automateaкeporiskeposic) Coachingreedbackkedos© Crm TemplateFilterRepostc) crmTemolateRepositorv.r© CrmTemplateRunRepositcC) DeviceRerositorv.oho© ElasticActivityRepository.l(c) EmailMessadeRenositorv.© GenericAiPromptReposito62© GroupRepository.php© InboxEmailBatchReposito65InboxRepository.php© InvitationRepository.php© JobRepository.php© LanguageRepository.php© MomentRepository.php6870© NotificationRepository.ph© ParticipantRepository.php© ParticipantSpeechReposit73 0© ParticipantStatsRepositor© PlaybookCategoryReposit75 C© PlaybookRepository.phpPlaylistActivityRepository.© PlaylistRepository.phpPlaylistShareRepository.p© QuestionRepository.php© RoleChangeEventRepositi© RoleRepository.php@ SearchRepositorv.ohr© SnapshotRepository.phpC) SocialAccountRevositorv.© StageRepository.phpC) SubscriotionSetRebositon87 ₫©TaskRepository.php(C) TeamA ContextRenositon© TeamDomainsRepository.© TeaminsightsRepository.p©TeamRepository.php910(C) ThemeRenositorv nhn@ TimeznnaRannsitorv nhnpublic const STATUS PROCESSING = 'processing';public const STATUS EATLED = 'failed';public const STATUS_PROCESSEQ = 'processed';public const PROVIDER_GSUITE = 'gsuite':protected Senumstatuses = 1Self::STATUS_FAILED,self::STATUS_PROCESSED,protected SenunPreviders = lself::PROVIDER_GSUITE,protected $table = 'text_relays';protected $fillable = ['email_provider','email_provider_id','email_ sent_at',"reciplent'origin_activity_id','activity_id',"code',orotected Saobends ="no strino'.orotected Shidden = П"uuid'• sso.onp© MailboxController.phpA SF jiminny@localhost]# HS_local (jiminny@localhost]A console (PROD] X A console [EU]© SsoController.phpA console [STAGING)©smsmessage.ong© SmsLength.php| A19 23 A v 632633634639637ORDER BY t.name,select * from users u join calendars c 1<->1..n: on c.user_id = u.idwhere u.team_id = 882;select * from activities where id = 74049485; # team 563 crm 537select * from activities where id = 73272382; # team 563 crm 537select * from activities where id = 64400389; # team 563 crm 537id = 58081273; # team563 crm 537select * from activities where id = 54520297: # team 563 crm 537select * from participants where activity_id = 58081273;select * from activities where crm_configuration_id = 537 and provider = 'aircall'select * from contacts where crm_configuration_id = 537 and id = 35957759;select * from accounts where crm_configuration_id = 537 and id = 19003658;select * from automated_report_results where id = 1976;select * from automated reportswhere id = 583;select * from activity_searches where id = 87714;select * from activity_search_filters where activity_search_id = 87714;SELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuidor uuid_to_bin(*47842446-af51-4bcb-854f-CC6560290101') = uuid;SELECT * FROM crm_configurations WHERE provider = 'hubspot';select * from rate_limits;automated_report_results where nedia tyRe = 'pdf' and status = 2and id IN (18,1872);select * fromSELECT * FROM users WHERE id IN (24623,29443,29613);SELECT * FROM automated_report_results WHERE Uvid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;select * from text_relays where created_at › '2026-05-01'# and id IN (32415, 32416);and id = 72412.select * from users where team_id = 2 and email like "%scott%' and id = 29510;SELECT * FROM activities WHERE uvid_to_bin('67cebfc2-ed56-44a2-8C68-7a0286ed8618') = uuid; # 79763436So jiminny040 A1 A40 V 65 ^sonnt keview • In 40m100% L2Wed 13 May 15:15:26U AskJiminnyReportActivityServiceTest~CascadeTrial Owner Role SeleRetactoring User EmaDashboard Activity Dereturn sthis->response->w1tharrav.'filters' = $filterSet->render(),+0 ..'activity-over-time' => Sthis->getActivityOverTime($user, $filterSet),Context set: CONTEXT_TEAM_INSIGHTS_ACTIVITY = 'team-insights-activity'2. Filter Set CreationFile: ActivitySearch.php:132-244O phpprivate function getTeamInsightsPageFilters(bool SisExport = false): FilterDefinitionCollectionreturn FilterDefinitionCollection:makeriterverintcion\reamensignes varerangeritrer.class,FilterDefinition Teaminsiahts Exists::class.Kestrictuserdroupscope..class,FilterDefinition Activitvchannel::classFilterDefinition\TeamInsights\ActivityDurationRange::class,FilterDefinition\TeamInsights\ActivityRecorded: :class, // KEY FILTERFulterDerinition Activitvivoe::class.2. Cilter Annlication Order3.1 Security Filters (Always Applied)RestrictTeam - Ensures user can only see their team's activitiesPectrictActivitvChannel /PoctrictActiustvGhannal.nhn×21-20)••phpAsk anvthina (84L)« Code SWF-1.6WN Windsurf Toams 51-7UTF.8f 4 spaces...
|
NULL
|
1686657028748437370
|
NULL
|
click
|
ocr
|
NULL
|
PhpStormEV favsco.jsProjectVIewINavigarecodeLarave PhpStormEV favsco.jsProjectVIewINavigarecodeLaravelg9 JY-20891-improve-sms-text-relaysRefactorloOlWindow©ActivityCommentRepositc©ActivityLogRepository-phy© ActivityMessageRepositol©ActivityMomentRepositor©Textmessagingservice.phg© ActivityProviderRepositor©ActivityRepository.php© ActivitySearchFilterReposActivityShareRepository.-F51@sclass |TextRelay extends Model© ActivityUploadSettingRep©AiPromptRepository.php53@AskAnythingRepository.pl54use Enums:use RequiresUUID;(c) Automateaкeporiskeposic) Coachingreedbackkedos© Crm TemplateFilterRepostc) crmTemolateRepositorv.r© CrmTemplateRunRepositcC) DeviceRerositorv.oho© ElasticActivityRepository.l(c) EmailMessadeRenositorv.© GenericAiPromptReposito62© GroupRepository.php© InboxEmailBatchReposito65InboxRepository.php© InvitationRepository.php© JobRepository.php© LanguageRepository.php© MomentRepository.php6870© NotificationRepository.ph© ParticipantRepository.php© ParticipantSpeechReposit73 0© ParticipantStatsRepositor© PlaybookCategoryReposit75 C© PlaybookRepository.phpPlaylistActivityRepository.© PlaylistRepository.phpPlaylistShareRepository.p© QuestionRepository.php© RoleChangeEventRepositi© RoleRepository.php@ SearchRepositorv.ohr© SnapshotRepository.phpC) SocialAccountRevositorv.© StageRepository.phpC) SubscriotionSetRebositon87 ₫©TaskRepository.php(C) TeamA ContextRenositon© TeamDomainsRepository.© TeaminsightsRepository.p©TeamRepository.php910(C) ThemeRenositorv nhn@ TimeznnaRannsitorv nhnpublic const STATUS PROCESSING = 'processing';public const STATUS EATLED = 'failed';public const STATUS_PROCESSEQ = 'processed';public const PROVIDER_GSUITE = 'gsuite':protected Senumstatuses = 1Self::STATUS_FAILED,self::STATUS_PROCESSED,protected SenunPreviders = lself::PROVIDER_GSUITE,protected $table = 'text_relays';protected $fillable = ['email_provider','email_provider_id','email_ sent_at',"reciplent'origin_activity_id','activity_id',"code',orotected Saobends ="no strino'.orotected Shidden = П"uuid'• sso.onp© MailboxController.phpA SF jiminny@localhost]# HS_local (jiminny@localhost]A console (PROD] X A console [EU]© SsoController.phpA console [STAGING)©smsmessage.ong© SmsLength.php| A19 23 A v 632633634639637ORDER BY t.name,select * from users u join calendars c 1<->1..n: on c.user_id = u.idwhere u.team_id = 882;select * from activities where id = 74049485; # team 563 crm 537select * from activities where id = 73272382; # team 563 crm 537select * from activities where id = 64400389; # team 563 crm 537id = 58081273; # team563 crm 537select * from activities where id = 54520297: # team 563 crm 537select * from participants where activity_id = 58081273;select * from activities where crm_configuration_id = 537 and provider = 'aircall'select * from contacts where crm_configuration_id = 537 and id = 35957759;select * from accounts where crm_configuration_id = 537 and id = 19003658;select * from automated_report_results where id = 1976;select * from automated reportswhere id = 583;select * from activity_searches where id = 87714;select * from activity_search_filters where activity_search_id = 87714;SELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuidor uuid_to_bin(*47842446-af51-4bcb-854f-CC6560290101') = uuid;SELECT * FROM crm_configurations WHERE provider = 'hubspot';select * from rate_limits;automated_report_results where nedia tyRe = 'pdf' and status = 2and id IN (18,1872);select * fromSELECT * FROM users WHERE id IN (24623,29443,29613);SELECT * FROM automated_report_results WHERE Uvid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;select * from text_relays where created_at › '2026-05-01'# and id IN (32415, 32416);and id = 72412.select * from users where team_id = 2 and email like "%scott%' and id = 29510;SELECT * FROM activities WHERE uvid_to_bin('67cebfc2-ed56-44a2-8C68-7a0286ed8618') = uuid; # 79763436So jiminny040 A1 A40 V 65 ^sonnt keview • In 40m100% L2Wed 13 May 15:15:26U AskJiminnyReportActivityServiceTest~CascadeTrial Owner Role SeleRetactoring User EmaDashboard Activity Dereturn sthis->response->w1tharrav.'filters' = $filterSet->render(),+0 ..'activity-over-time' => Sthis->getActivityOverTime($user, $filterSet),Context set: CONTEXT_TEAM_INSIGHTS_ACTIVITY = 'team-insights-activity'2. Filter Set CreationFile: ActivitySearch.php:132-244O phpprivate function getTeamInsightsPageFilters(bool SisExport = false): FilterDefinitionCollectionreturn FilterDefinitionCollection:makeriterverintcion\reamensignes varerangeritrer.class,FilterDefinition Teaminsiahts Exists::class.Kestrictuserdroupscope..class,FilterDefinition Activitvchannel::classFilterDefinition\TeamInsights\ActivityDurationRange::class,FilterDefinition\TeamInsights\ActivityRecorded: :class, // KEY FILTERFulterDerinition Activitvivoe::class.2. Cilter Annlication Order3.1 Security Filters (Always Applied)RestrictTeam - Ensures user can only see their team's activitiesPectrictActivitvChannel /PoctrictActiustvGhannal.nhn×21-20)••phpAsk anvthina (84L)« Code SWF-1.6WN Windsurf Toams 51-7UTF.8f 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
33554
|
1274
|
19
|
2026-05-13T10:33:12.151479+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668392151_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
40
1
40
64
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993
SELECT * FROM users WHERE id = 25061;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 994;
SELECT * FROM crm_profiles WHERE user_id = 25061;
select * from crm_configurations where id = 834;
SELECT * FROM teams WHERE id = 882;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;
SELECT * FROM contacts where crm_configuration_id = 834;
SELECT * FROM opportunities WHERE team_id = 933
# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');
AND id IN (8482561,18352941,19042734,19232139,19445140,19472541);
SELECT * FROM opportunity_contacts
WHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 485; #
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
select crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id
where crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')
# and l.converted_at IS NOT NULL
;
# [PASSWORD_DOTS]
SELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')
and opportunity_id IS NULL
order by id desc;
SELECT * FROM teams WHERE id = 604; # 598
SELECT * FROM activities WHERE id = 74410828; # [EMAIL]
SELECT * FROM accounts WHERE id = 20068382;
SELECT * FROM accounts WHERE id = 35186038;
SELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 559 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;
select * from sidekick_settings where team_id = 781;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100
SELECT * FROM crm_layouts WHERE crm_configuration_id = 711;
SELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL
and is_internal = 0 and status = 'completed'
order by id desc;
SELECT * FROM crm_layout_entities
WHERE crm_layout_id IN (2352, 2353);
;
SELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 556 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;
SELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;
select * from contacts
where crm_configuration_id = 530
and crm_provider_id = 872252;
select * from activities where crm_configuration_id = 530
and user_id = 14343 and type like '%softphone%'
and created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);
SELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t
JOIN crm_configurations c ON t.id = c.team_id
WHERE t.status = 'active';
SELECT * FROM teams where id = 1091;
SELECT * FROM crm_configurations where team_id = 1091;
SELECT * FROM activity_providers where team_id = 1091;
SELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT * FROM teams WHERE name LIKE '%Leadventure%';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1091 and sa.provider = 'salesforce';
SELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812
SELECT * FROM teams where id = 862;
SELECT * FROM crm_configurations where team_id = 862;
SELECT * FROM activity_providers where team_id = 862;
SELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT t.id, crm.id, crm.provider, ap.* FROM teams t
join crm_configurations crm on t.id = crm.team_id
join activity_providers ap on t.id = ap.team_id
where t.status = 'active' and ap.is_enabled = 1
and crm.provider = 'hubspot'
and ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',
'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');
SELECT * FROM teams where id = 1068;
SELECT * FROM crm_configurations where team_id = 1068;
SELECT * FROM activity_providers where team_id = 1068;
SELECT * FROM activities a
where crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')
and a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'
)
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by a.id desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1068 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262
SELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
select * from crm_layouts where crm_configuration_id = 834;
select * from crm_layout_entities where crm_layout_id = 2780;
select * from crm_fields where id IN (321153,321192,321193,321194);
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1057 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8
SELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20
SELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10
SELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #
SELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;
select * from users where team_id = 51; # 7783
SELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130
select * from activity_searches where user_id = 7783;
select * from activity_search_filters where activity_search_id IN (32291, 32292);
SELECT asf.activity_search_id, asf.id, asf.value
FROM activity_search_filters asf
WHERE asf.filter = 'group_id'
AND asf.value IN (
SELECT CONCAT(
HEX(SUBSTR(uuid, 5, 4)), '-',
HEX(SUBSTR(uuid, 3, 2)), '-',
HEX(SUBSTR(uuid, 1, 2)), '-',
HEX(SUBSTR(uuid, 9, 2)), '-',
HEX(SUBSTR(uuid, 11))
)
FROM groups
WHERE deleted_at IS NOT NULL
);
SELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where provider = 'hubspot';
SELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133
SELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null
# [PASSWORD_DOTS]
select * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';
select
cp.*
# DISTINCT t.id
# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields
FROM crm_profiles cp
JOIN crm_configurations crm on crm.id = cp.crm_configuration_id
JOIN users u on u.id = cp.user_id
JOIN teams t ON t.id = crm.team_id
WHERE crm.provider = 'salesforce' and t.status = 'active'
and cp.archived_at IS NULL and u.deleted_at IS NULL
and t.id NOT IN (1093)
and t.id = 2
and cp.contact_fields IS NULL;
# and c.crm_provider_id = '003Uu00000ojD4NIAU';
SELECT * FROM users WHERE id = 26484;
SELECT * FROM crm_profiles WHERE user_id = 26484;
SELECT * FROM social_accounts WHERE sociable_id = 26484;
SELECT * FROM crm_configurations where provider = 'salesforce';
select * from users where id IN (10022, 10403);
select * from users where team_id IN (526);
select * from teams where id IN (526, 532);
select * from crm_configurations where id IN (500, 516);
select * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);
select * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 526 and sa.provider = 'salesforce';
select * from team_settings where team_id IN (526, 532);
select * from users where id IN (22824);
select * from crm_profiles where crm_configuration_id IN (1026);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1093 and sa.provider = 'salesforce';
select * from teams where id = 1099;
select * from users where id = 29643
select * from activity_processing_states;
SELECT * FROM teams where name LIKE '%Fare%'; # 233
SELECT * FROM opportunities where crm_configuration_id = 215
# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'
;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1088 and sa.provider = 'hubspot';
SELECT * FROM teams order by updated_at DESC
SELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account
select * from crm_configurations where provider = 'pipedrive';
select * from teams where id = 957;
select * from crm_configurations where id = 957;
SELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743
SELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;
select * from users where team_id = 1; # 26726 - Gabriela Dureva
SELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific
select * from activities where user_id = 26726 order by id desc;
select * from contacts where crm_configuration_id = 1
and email IN ('[EMAIL]', '[EMAIL]'); # 2094416, 2093620
SELECT * FROM contacts WHERE id = 6284931;
SELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id
WHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;
select * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);
select * from crm_configurations where id = 1;
43801692-1aeb-32ce-acba-5b80a479701a
44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b
405975c0-b3d0-7aaa-821f-09d59cae6dd1
4caf848d-4bed-2299-b248-7788d41f9fca
49bedc3f-f196-eef3-89c3-dea6a3b4aa63
43420989-a09d-b8f8-9806-c8bbf7a02aac
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
SELECT * FROM activities WHERE id = 75461988;
SELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;
select * from contacts where id = 17900517;
select * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id
where crm.provider != 'salesforce';
select * from users where id = 21047;
SELECT * FROM crm_configurations WHERE id = 892;
SELECT * FROM teams WHERE id = 942;
select * from opportunities where team_id = 942 order by updated_at desc;
select * from contacts where team_id = 942 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 942 and sa.provider = 'hubspot';
SELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430
SELECT * FROM crm_configurations WHERE id = 1;
SELECT * FROM teams WHERE crm_id = 1;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
select id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1
SELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430
select * from teams where id = 852;
select * from groups where id = 2286;
select * from sidekick_settings where team_id = 852;
select * from default_activity_types where team_id = 852;
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1 AND u.deleted_at IS NULL
AND u.crm_required = 1
AND u.team_id = 1
ORDER BY u.team_id;
SELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (
18481
);
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1
AND u.deleted_at IS NULL
AND u.crm_required = 1
# AND u.team_id = 1
AND p.id IS NULL -- Move this condition to WHERE clause
ORDER BY u.team_id;
SELECT * FROM opportunities WHERE id = 20002609;
select * from teams where id = 1122; # Velatir, 29953 - [EMAIL]
select * from crm_configurations where id = 1060;
select * from crm_layouts where crm_configuration_id = 1060;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1122 and sa.provider = 'hubspot';
select * from opportunities where team_id = 1122 order by updated_at desc;
select * from crm_field_data where object_type = 'contact';
SELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 248 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS
SELECT * FROM users where id = 24115;
SELECT * FROM accounts where id = 4002896;
SELECT * FROM teams WHERE name LIKE '%adswerve%';
SELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN ("0069N000003GIQ9QAO","0061r000019yGP9AAM","0066900001S2KWlAAN","0066900001TDpj2AAD","0066900001b8uEwAAI","0069N000001rQi0QAE","006QF00000KD40mYAD","006QF00000LzpRJYAZ","0069N000002uomtQAA","0069N000002xlMLQAY","0066900001NV6ubAAD","0061r00001HJp45AAD","006QF00000uTlUoYAK","006QF00000v0bZqYAI");
SELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203
SELECT u.id, u.email, ac.name, a.* FROM activities a
JOIN users u ON a.user_id = u.id
JOIN accounts ac ON a.account_id = ac.id
WHERE
uuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or
uuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or
uuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;
select * from users where id = 5825;
SELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;
select * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;
19594, 862
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 862 and sa.provider = 'salesforce';
select * from automated_reports where id = 36;
select ar.frequency, r.*, ar.* from automated_report_results r
join automated_reports ar on r.report_id = ar.id
where ar.frequency != 'one_off';
select s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;
select * from nudges n where n.activity_search_id
select * from teams where created_at > '2026-03-09';
SELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;
select * from users where team_id = 1 and name like '%Lukas%'; # 7160
SELECT * FROM teams WHERE id = 575;
select * from opportunities where team_id = 575;
SELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,
select * from opportunities where team_id = 1126;
SELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,
select * from opportunities where team_id = 1125;
select * from contacts c
where c.team_id = 882;
SELECT * FROM activities WHERE id = 76822967;
SELECT * FROM crm_profiles WHERE user_id = 15440;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 555;
SELECT * FROM crm_configurations WHERE id = 555;
SELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 581 and sa.provider = 'salesforce';
SELECT * FROM automated_report_results order by id desc;
select * from features;
select * from team_features where feature_id = 40;
select * from teams where id = 556;
select * from automated_reports;
where id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , ["pdf","podcast"]
SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;
select * from automated_report_results order by id desc;
SELECT * FROM automated_report_results WHERE id = 1919;
select * from automated_report_results WHERE report_id = 54;
select * from opportunities where id = 7594349;
SELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - [EMAIL]
select * from playbooks where team_id = 711; # event 226147
SELECT * FROM playbook_categories WHERE playbook_id = 5515;
SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';
SELECT * FROM crm_fields WHERE id = 226147;
SELECT * FROM crm_field_values WHERE crm_field_id = 226147;
SELECT * FROM crm_configurations WHERE id = 692;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 711 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;
select * from leads;
select * from calendars;
SELECT
t.id AS team_id,
t.name,
LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain
FROM teams t
JOIN users u ON u.team_id = t.id
JOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'
LEFT JOIN team_domains td
ON td.team_id = t.id
AND td.deleted_at IS NULL
AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))
GROUP BY t.id, t.name, calendar_domain
ORDER BY t.name, calendar_domain;
select * from users u join calendars c on c.user_id = u.id
where u.team_id = 882;
select * from activities where id = 74049485; # team 563 crm 537
select * from activities where id = 73272382; # team 563 crm 537
select * from activities where id = 64400389; # team 563 crm 537
select * from activities where id = 58081273; # team 563 crm 537
select * from activities where id = 54520297; # team 563 crm 537
select * from participants where activity_id = 58081273;
select * from activities where crm_configuration_id = 537 and provider = 'aircall'
and account_id = 19003658 order by updated_at desc;
select * from contacts where crm_configuration_id = 537 and id = 35957759;
select * from accounts where crm_configuration_id = 537 and id = 19003658;
select * from automated_report_results where id = 1976;
select * from automated_reports where id = 583;
select * from activity_searches where id = 87714;
select * from activity_search_filters where activity_search_id = 87714;
SELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid
or uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;
SELECT * FROM crm_configurations WHERE provider = 'hubspot';
select * from rate_limits;
select * from automated_report_results where media_type = 'pdf' and status = 2
and id IN (18, 1872);
select * from automated_reports where id = 54;
SELECT * FROM users WHERE id IN (24623,29443,29613);
SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
InviteUserToTeamAction.php, class
MarkUserAsOnboardableAction.php, class
SyncRecordingFlagsAction.php, class
UpdateTeamMemberAction.php, class
UpdateUserRolesAction.php, class
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot, folder
MobileSettings, folder
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech
PartitionedCookie
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary
Twilio
Uploader
UrlGenerator
Utility
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php
BullhornCommandAbstract.php
BullhornPingCommand.php
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php, final class
CleanDuplicateFieldDataCommand.php, class
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php, class
SetupActivityTypeForFollowUp.php, final class
SetupCloseCrm.php, class
SetupCopperCrm.php, class
SetupCrmCommand.php, abstract class
SetupLayouts.php, class
SyncAccount.php, class
SyncContact.php, class
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzing…","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"40","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"40","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"64","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993\nSELECT * FROM users WHERE id = 25061;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 994;\nSELECT * FROM crm_profiles WHERE user_id = 25061;\n\nselect * from crm_configurations where id = 834;\nSELECT * FROM teams WHERE id = 882;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;\n\nSELECT * FROM contacts where crm_configuration_id = 834;\nSELECT * FROM opportunities WHERE team_id = 933\n# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');\nAND id IN (8482561,18352941,19042734,19232139,19445140,19472541);\nSELECT * FROM opportunity_contacts\nWHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 485; #\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nselect crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id\nwhere crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')\n# and l.converted_at IS NOT NULL\n;\n\n# ********************************************************************\nSELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')\nand opportunity_id IS NULL\norder by id desc;\n\nSELECT * FROM teams WHERE id = 604; # 598\nSELECT * FROM activities WHERE id = 74410828; # chelseaw@allvoices.co\nSELECT * FROM accounts WHERE id = 20068382;\nSELECT * FROM accounts WHERE id = 35186038;\n\nSELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 559 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;\nselect * from sidekick_settings where team_id = 781;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100\n\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 711;\nSELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL\nand is_internal = 0 and status = 'completed'\norder by id desc;\n\nSELECT * FROM crm_layout_entities\nWHERE crm_layout_id IN (2352, 2353);\n;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 556 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;\nSELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;\nselect * from contacts\nwhere crm_configuration_id = 530\nand crm_provider_id = 872252;\n\nselect * from activities where crm_configuration_id = 530\nand user_id = 14343 and type like '%softphone%'\nand created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);\n\n\nSELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t\nJOIN crm_configurations c ON t.id = c.team_id\nWHERE t.status = 'active';\n\nSELECT * FROM teams where id = 1091;\nSELECT * FROM crm_configurations where team_id = 1091;\nSELECT * FROM activity_providers where team_id = 1091;\nSELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT * FROM teams WHERE name LIKE '%Leadventure%';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1091 and sa.provider = 'salesforce';\n\nSELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812\nSELECT * FROM teams where id = 862;\nSELECT * FROM crm_configurations where team_id = 862;\nSELECT * FROM activity_providers where team_id = 862;\nSELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT t.id, crm.id, crm.provider, ap.* FROM teams t\njoin crm_configurations crm on t.id = crm.team_id\njoin activity_providers ap on t.id = ap.team_id\nwhere t.status = 'active' and ap.is_enabled = 1\nand crm.provider = 'hubspot'\nand ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',\n 'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');\n\nSELECT * FROM teams where id = 1068;\nSELECT * FROM crm_configurations where team_id = 1068;\nSELECT * FROM activity_providers where team_id = 1068;\n\nSELECT * FROM activities a\nwhere crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')\nand a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'\n )\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by a.id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1068 and sa.provider = 'hubspot';\n\n# ********************************************************************\n# ********************************************************************\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262\nSELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\nselect * from crm_layouts where crm_configuration_id = 834;\nselect * from crm_layout_entities where crm_layout_id = 2780;\nselect * from crm_fields where id IN (321153,321192,321193,321194);\n\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1057 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8\n\nSELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20\n\nSELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10\n\nSELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #\n\nSELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;\nselect * from users where team_id = 51; # 7783\nSELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130\nselect * from activity_searches where user_id = 7783;\nselect * from activity_search_filters where activity_search_id IN (32291, 32292);\n\nSELECT asf.activity_search_id, asf.id, asf.value\nFROM activity_search_filters asf\nWHERE asf.filter = 'group_id'\nAND asf.value IN (\n SELECT CONCAT(\n HEX(SUBSTR(uuid, 5, 4)), '-',\n HEX(SUBSTR(uuid, 3, 2)), '-',\n HEX(SUBSTR(uuid, 1, 2)), '-',\n HEX(SUBSTR(uuid, 9, 2)), '-',\n HEX(SUBSTR(uuid, 11))\n )\n FROM groups\n WHERE deleted_at IS NOT NULL\n);\n\nSELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th\n# ********************************************************************\nSELECT * FROM crm_configurations where provider = 'hubspot';\nSELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133\nSELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null\n# ********************************************************************\n\nselect * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';\nselect\n cp.*\n# DISTINCT t.id\n# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields\nFROM crm_profiles cp\nJOIN crm_configurations crm on crm.id = cp.crm_configuration_id\nJOIN users u on u.id = cp.user_id\nJOIN teams t ON t.id = crm.team_id\nWHERE crm.provider = 'salesforce' and t.status = 'active'\n and cp.archived_at IS NULL and u.deleted_at IS NULL\n and t.id NOT IN (1093)\n and t.id = 2\n and cp.contact_fields IS NULL;\n# and c.crm_provider_id = '003Uu00000ojD4NIAU';\n\nSELECT * FROM users WHERE id = 26484;\nSELECT * FROM crm_profiles WHERE user_id = 26484;\nSELECT * FROM social_accounts WHERE sociable_id = 26484;\nSELECT * FROM crm_configurations where provider = 'salesforce';\nselect * from users where id IN (10022, 10403);\nselect * from users where team_id IN (526);\nselect * from teams where id IN (526, 532);\nselect * from crm_configurations where id IN (500, 516);\nselect * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);\nselect * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 526 and sa.provider = 'salesforce';\nselect * from team_settings where team_id IN (526, 532);\n\nselect * from users where id IN (22824);\nselect * from crm_profiles where crm_configuration_id IN (1026);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1093 and sa.provider = 'salesforce';\n\nselect * from teams where id = 1099;\nselect * from users where id = 29643\n\nselect * from activity_processing_states;\n\nSELECT * FROM teams where name LIKE '%Fare%'; # 233\nSELECT * FROM opportunities where crm_configuration_id = 215\n# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'\n;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1088 and sa.provider = 'hubspot';\n\nSELECT * FROM teams order by updated_at DESC\nSELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account\n\nselect * from crm_configurations where provider = 'pipedrive';\n\nselect * from teams where id = 957;\nselect * from crm_configurations where id = 957;\n\nSELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743\nSELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;\n\nselect * from users where team_id = 1; # 26726 - Gabriela Dureva\nSELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific\nselect * from activities where user_id = 26726 order by id desc;\nselect * from contacts where crm_configuration_id = 1\nand email IN ('charlotte.ward@prolific.com', 'frankie.bryant@prolific.com'); # 2094416, 2093620\nSELECT * FROM contacts WHERE id = 6284931;\n\nSELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id\nWHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;\n\nselect * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);\nselect * from crm_configurations where id = 1;\n\n43801692-1aeb-32ce-acba-5b80a479701a\n44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b\n405975c0-b3d0-7aaa-821f-09d59cae6dd1\n4caf848d-4bed-2299-b248-7788d41f9fca\n49bedc3f-f196-eef3-89c3-dea6a3b4aa63\n43420989-a09d-b8f8-9806-c8bbf7a02aac\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nSELECT * FROM activities WHERE id = 75461988;\n\nSELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;\n\nselect * from contacts where id = 17900517;\n\nselect * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id\nwhere crm.provider != 'salesforce';\n\nselect * from users where id = 21047;\nSELECT * FROM crm_configurations WHERE id = 892;\nSELECT * FROM teams WHERE id = 942;\nselect * from opportunities where team_id = 942 order by updated_at desc;\nselect * from contacts where team_id = 942 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 942 and sa.provider = 'hubspot';\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430\nSELECT * FROM crm_configurations WHERE id = 1;\nSELECT * FROM teams WHERE crm_id = 1;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nselect id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1\nSELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430\n\nselect * from teams where id = 852;\nselect * from groups where id = 2286;\nselect * from sidekick_settings where team_id = 852;\nselect * from default_activity_types where team_id = 852;\n\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1 AND u.deleted_at IS NULL\nAND u.crm_required = 1\nAND u.team_id = 1\nORDER BY u.team_id;\n\nSELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (\n18481\n );\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1\n AND u.deleted_at IS NULL\n AND u.crm_required = 1\n# AND u.team_id = 1\n AND p.id IS NULL -- Move this condition to WHERE clause\nORDER BY u.team_id;\n\nSELECT * FROM opportunities WHERE id = 20002609;\nselect * from teams where id = 1122; # Velatir, 29953 - christian@velatir.com\nselect * from crm_configurations where id = 1060;\nselect * from crm_layouts where crm_configuration_id = 1060;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1122 and sa.provider = 'hubspot';\nselect * from opportunities where team_id = 1122 order by updated_at desc;\n\nselect * from crm_field_data where object_type = 'contact';\n\nSELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 248 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS\nSELECT * FROM users where id = 24115;\nSELECT * FROM accounts where id = 4002896;\nSELECT * FROM teams WHERE name LIKE '%adswerve%';\nSELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN (\"0069N000003GIQ9QAO\",\"0061r000019yGP9AAM\",\"0066900001S2KWlAAN\",\"0066900001TDpj2AAD\",\"0066900001b8uEwAAI\",\"0069N000001rQi0QAE\",\"006QF00000KD40mYAD\",\"006QF00000LzpRJYAZ\",\"0069N000002uomtQAA\",\"0069N000002xlMLQAY\",\"0066900001NV6ubAAD\",\"0061r00001HJp45AAD\",\"006QF00000uTlUoYAK\",\"006QF00000v0bZqYAI\");\nSELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203\n\nSELECT u.id, u.email, ac.name, a.* FROM activities a\nJOIN users u ON a.user_id = u.id\nJOIN accounts ac ON a.account_id = ac.id\nWHERE\nuuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or\nuuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or\nuuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;\n\nselect * from users where id = 5825;\nSELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;\n\nselect * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;\n19594, 862\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 862 and sa.provider = 'salesforce';\n\nselect * from automated_reports where id = 36;\nselect ar.frequency, r.*, ar.* from automated_report_results r\njoin automated_reports ar on r.report_id = ar.id\nwhere ar.frequency != 'one_off';\n\nselect s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;\nselect * from nudges n where n.activity_search_id\n\nselect * from teams where created_at > '2026-03-09';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;\n\nselect * from users where team_id = 1 and name like '%Lukas%'; # 7160\n\nSELECT * FROM teams WHERE id = 575;\nselect * from opportunities where team_id = 575;\nSELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,\nselect * from opportunities where team_id = 1126;\nSELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,\nselect * from opportunities where team_id = 1125;\nselect * from contacts c\nwhere c.team_id = 882;\n\nSELECT * FROM activities WHERE id = 76822967;\nSELECT * FROM crm_profiles WHERE user_id = 15440;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 555;\nSELECT * FROM crm_configurations WHERE id = 555;\nSELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 581 and sa.provider = 'salesforce';\n\nSELECT * FROM automated_report_results order by id desc;\n\nselect * from features;\nselect * from team_features where feature_id = 40;\n\nselect * from teams where id = 556;\n\nselect * from automated_reports;\nwhere id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , [\"pdf\",\"podcast\"]\nSELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;\nselect * from automated_report_results order by id desc;\nSELECT * FROM automated_report_results WHERE id = 1919;\n\nselect * from automated_report_results WHERE report_id = 54;\n\nselect * from opportunities where id = 7594349;\n\nSELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - jiminnyintegration@lesmills.com\nselect * from playbooks where team_id = 711; # event 226147\nSELECT * FROM playbook_categories WHERE playbook_id = 5515;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';\nSELECT * FROM crm_fields WHERE id = 226147;\nSELECT * FROM crm_field_values WHERE crm_field_id = 226147;\n\nSELECT * FROM crm_configurations WHERE id = 692;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 711 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;\n\nselect * from leads;\n\nselect * from calendars;\n\nSELECT\n t.id AS team_id,\n t.name,\n LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain\nFROM teams t\nJOIN users u ON u.team_id = t.id\nJOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'\nLEFT JOIN team_domains td\n ON td.team_id = t.id\n AND td.deleted_at IS NULL\n AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))\nGROUP BY t.id, t.name, calendar_domain\nORDER BY t.name, calendar_domain;\n\nselect * from users u join calendars c on c.user_id = u.id\nwhere u.team_id = 882;\n\n\nselect * from activities where id = 74049485; # team 563 crm 537\nselect * from activities where id = 73272382; # team 563 crm 537\nselect * from activities where id = 64400389; # team 563 crm 537\nselect * from activities where id = 58081273; # team 563 crm 537\nselect * from activities where id = 54520297; # team 563 crm 537\nselect * from participants where activity_id = 58081273;\n\nselect * from activities where crm_configuration_id = 537 and provider = 'aircall'\nand account_id = 19003658 order by updated_at desc;\n\nselect * from contacts where crm_configuration_id = 537 and id = 35957759;\nselect * from accounts where crm_configuration_id = 537 and id = 19003658;\n\nselect * from automated_report_results where id = 1976;\nselect * from automated_reports where id = 583;\nselect * from activity_searches where id = 87714;\nselect * from activity_search_filters where activity_search_id = 87714;\n\nSELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid\nor uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;\n\nSELECT * FROM crm_configurations WHERE provider = 'hubspot';\nselect * from rate_limits;\n\nselect * from automated_report_results where media_type = 'pdf' and status = 2\nand id IN (18, 1872);\nselect * from automated_reports where id = 54;\nSELECT * FROM users WHERE id IN (24623,29443,29613);\n\nSELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;","depth":4,"on_screen":true,"value":"SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993\nSELECT * FROM users WHERE id = 25061;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 994;\nSELECT * FROM crm_profiles WHERE user_id = 25061;\n\nselect * from crm_configurations where id = 834;\nSELECT * FROM teams WHERE id = 882;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;\n\nSELECT * FROM contacts where crm_configuration_id = 834;\nSELECT * FROM opportunities WHERE team_id = 933\n# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');\nAND id IN (8482561,18352941,19042734,19232139,19445140,19472541);\nSELECT * FROM opportunity_contacts\nWHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 485; #\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nselect crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id\nwhere crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')\n# and l.converted_at IS NOT NULL\n;\n\n# ********************************************************************\nSELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')\nand opportunity_id IS NULL\norder by id desc;\n\nSELECT * FROM teams WHERE id = 604; # 598\nSELECT * FROM activities WHERE id = 74410828; # chelseaw@allvoices.co\nSELECT * FROM accounts WHERE id = 20068382;\nSELECT * FROM accounts WHERE id = 35186038;\n\nSELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 559 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;\nselect * from sidekick_settings where team_id = 781;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100\n\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 711;\nSELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL\nand is_internal = 0 and status = 'completed'\norder by id desc;\n\nSELECT * FROM crm_layout_entities\nWHERE crm_layout_id IN (2352, 2353);\n;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 556 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;\nSELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;\nselect * from contacts\nwhere crm_configuration_id = 530\nand crm_provider_id = 872252;\n\nselect * from activities where crm_configuration_id = 530\nand user_id = 14343 and type like '%softphone%'\nand created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);\n\n\nSELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t\nJOIN crm_configurations c ON t.id = c.team_id\nWHERE t.status = 'active';\n\nSELECT * FROM teams where id = 1091;\nSELECT * FROM crm_configurations where team_id = 1091;\nSELECT * FROM activity_providers where team_id = 1091;\nSELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT * FROM teams WHERE name LIKE '%Leadventure%';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1091 and sa.provider = 'salesforce';\n\nSELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812\nSELECT * FROM teams where id = 862;\nSELECT * FROM crm_configurations where team_id = 862;\nSELECT * FROM activity_providers where team_id = 862;\nSELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT t.id, crm.id, crm.provider, ap.* FROM teams t\njoin crm_configurations crm on t.id = crm.team_id\njoin activity_providers ap on t.id = ap.team_id\nwhere t.status = 'active' and ap.is_enabled = 1\nand crm.provider = 'hubspot'\nand ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',\n 'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');\n\nSELECT * FROM teams where id = 1068;\nSELECT * FROM crm_configurations where team_id = 1068;\nSELECT * FROM activity_providers where team_id = 1068;\n\nSELECT * FROM activities a\nwhere crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')\nand a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'\n )\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by a.id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1068 and sa.provider = 'hubspot';\n\n# ********************************************************************\n# ********************************************************************\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262\nSELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\nselect * from crm_layouts where crm_configuration_id = 834;\nselect * from crm_layout_entities where crm_layout_id = 2780;\nselect * from crm_fields where id IN (321153,321192,321193,321194);\n\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1057 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8\n\nSELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20\n\nSELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10\n\nSELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #\n\nSELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;\nselect * from users where team_id = 51; # 7783\nSELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130\nselect * from activity_searches where user_id = 7783;\nselect * from activity_search_filters where activity_search_id IN (32291, 32292);\n\nSELECT asf.activity_search_id, asf.id, asf.value\nFROM activity_search_filters asf\nWHERE asf.filter = 'group_id'\nAND asf.value IN (\n SELECT CONCAT(\n HEX(SUBSTR(uuid, 5, 4)), '-',\n HEX(SUBSTR(uuid, 3, 2)), '-',\n HEX(SUBSTR(uuid, 1, 2)), '-',\n HEX(SUBSTR(uuid, 9, 2)), '-',\n HEX(SUBSTR(uuid, 11))\n )\n FROM groups\n WHERE deleted_at IS NOT NULL\n);\n\nSELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th\n# ********************************************************************\nSELECT * FROM crm_configurations where provider = 'hubspot';\nSELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133\nSELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null\n# ********************************************************************\n\nselect * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';\nselect\n cp.*\n# DISTINCT t.id\n# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields\nFROM crm_profiles cp\nJOIN crm_configurations crm on crm.id = cp.crm_configuration_id\nJOIN users u on u.id = cp.user_id\nJOIN teams t ON t.id = crm.team_id\nWHERE crm.provider = 'salesforce' and t.status = 'active'\n and cp.archived_at IS NULL and u.deleted_at IS NULL\n and t.id NOT IN (1093)\n and t.id = 2\n and cp.contact_fields IS NULL;\n# and c.crm_provider_id = '003Uu00000ojD4NIAU';\n\nSELECT * FROM users WHERE id = 26484;\nSELECT * FROM crm_profiles WHERE user_id = 26484;\nSELECT * FROM social_accounts WHERE sociable_id = 26484;\nSELECT * FROM crm_configurations where provider = 'salesforce';\nselect * from users where id IN (10022, 10403);\nselect * from users where team_id IN (526);\nselect * from teams where id IN (526, 532);\nselect * from crm_configurations where id IN (500, 516);\nselect * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);\nselect * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 526 and sa.provider = 'salesforce';\nselect * from team_settings where team_id IN (526, 532);\n\nselect * from users where id IN (22824);\nselect * from crm_profiles where crm_configuration_id IN (1026);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1093 and sa.provider = 'salesforce';\n\nselect * from teams where id = 1099;\nselect * from users where id = 29643\n\nselect * from activity_processing_states;\n\nSELECT * FROM teams where name LIKE '%Fare%'; # 233\nSELECT * FROM opportunities where crm_configuration_id = 215\n# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'\n;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1088 and sa.provider = 'hubspot';\n\nSELECT * FROM teams order by updated_at DESC\nSELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account\n\nselect * from crm_configurations where provider = 'pipedrive';\n\nselect * from teams where id = 957;\nselect * from crm_configurations where id = 957;\n\nSELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743\nSELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;\n\nselect * from users where team_id = 1; # 26726 - Gabriela Dureva\nSELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific\nselect * from activities where user_id = 26726 order by id desc;\nselect * from contacts where crm_configuration_id = 1\nand email IN ('charlotte.ward@prolific.com', 'frankie.bryant@prolific.com'); # 2094416, 2093620\nSELECT * FROM contacts WHERE id = 6284931;\n\nSELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id\nWHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;\n\nselect * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);\nselect * from crm_configurations where id = 1;\n\n43801692-1aeb-32ce-acba-5b80a479701a\n44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b\n405975c0-b3d0-7aaa-821f-09d59cae6dd1\n4caf848d-4bed-2299-b248-7788d41f9fca\n49bedc3f-f196-eef3-89c3-dea6a3b4aa63\n43420989-a09d-b8f8-9806-c8bbf7a02aac\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nSELECT * FROM activities WHERE id = 75461988;\n\nSELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;\n\nselect * from contacts where id = 17900517;\n\nselect * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id\nwhere crm.provider != 'salesforce';\n\nselect * from users where id = 21047;\nSELECT * FROM crm_configurations WHERE id = 892;\nSELECT * FROM teams WHERE id = 942;\nselect * from opportunities where team_id = 942 order by updated_at desc;\nselect * from contacts where team_id = 942 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 942 and sa.provider = 'hubspot';\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430\nSELECT * FROM crm_configurations WHERE id = 1;\nSELECT * FROM teams WHERE crm_id = 1;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nselect id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1\nSELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430\n\nselect * from teams where id = 852;\nselect * from groups where id = 2286;\nselect * from sidekick_settings where team_id = 852;\nselect * from default_activity_types where team_id = 852;\n\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1 AND u.deleted_at IS NULL\nAND u.crm_required = 1\nAND u.team_id = 1\nORDER BY u.team_id;\n\nSELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (\n18481\n );\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1\n AND u.deleted_at IS NULL\n AND u.crm_required = 1\n# AND u.team_id = 1\n AND p.id IS NULL -- Move this condition to WHERE clause\nORDER BY u.team_id;\n\nSELECT * FROM opportunities WHERE id = 20002609;\nselect * from teams where id = 1122; # Velatir, 29953 - christian@velatir.com\nselect * from crm_configurations where id = 1060;\nselect * from crm_layouts where crm_configuration_id = 1060;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1122 and sa.provider = 'hubspot';\nselect * from opportunities where team_id = 1122 order by updated_at desc;\n\nselect * from crm_field_data where object_type = 'contact';\n\nSELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 248 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS\nSELECT * FROM users where id = 24115;\nSELECT * FROM accounts where id = 4002896;\nSELECT * FROM teams WHERE name LIKE '%adswerve%';\nSELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN (\"0069N000003GIQ9QAO\",\"0061r000019yGP9AAM\",\"0066900001S2KWlAAN\",\"0066900001TDpj2AAD\",\"0066900001b8uEwAAI\",\"0069N000001rQi0QAE\",\"006QF00000KD40mYAD\",\"006QF00000LzpRJYAZ\",\"0069N000002uomtQAA\",\"0069N000002xlMLQAY\",\"0066900001NV6ubAAD\",\"0061r00001HJp45AAD\",\"006QF00000uTlUoYAK\",\"006QF00000v0bZqYAI\");\nSELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203\n\nSELECT u.id, u.email, ac.name, a.* FROM activities a\nJOIN users u ON a.user_id = u.id\nJOIN accounts ac ON a.account_id = ac.id\nWHERE\nuuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or\nuuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or\nuuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;\n\nselect * from users where id = 5825;\nSELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;\n\nselect * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;\n19594, 862\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 862 and sa.provider = 'salesforce';\n\nselect * from automated_reports where id = 36;\nselect ar.frequency, r.*, ar.* from automated_report_results r\njoin automated_reports ar on r.report_id = ar.id\nwhere ar.frequency != 'one_off';\n\nselect s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;\nselect * from nudges n where n.activity_search_id\n\nselect * from teams where created_at > '2026-03-09';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;\n\nselect * from users where team_id = 1 and name like '%Lukas%'; # 7160\n\nSELECT * FROM teams WHERE id = 575;\nselect * from opportunities where team_id = 575;\nSELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,\nselect * from opportunities where team_id = 1126;\nSELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,\nselect * from opportunities where team_id = 1125;\nselect * from contacts c\nwhere c.team_id = 882;\n\nSELECT * FROM activities WHERE id = 76822967;\nSELECT * FROM crm_profiles WHERE user_id = 15440;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 555;\nSELECT * FROM crm_configurations WHERE id = 555;\nSELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 581 and sa.provider = 'salesforce';\n\nSELECT * FROM automated_report_results order by id desc;\n\nselect * from features;\nselect * from team_features where feature_id = 40;\n\nselect * from teams where id = 556;\n\nselect * from automated_reports;\nwhere id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , [\"pdf\",\"podcast\"]\nSELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;\nselect * from automated_report_results order by id desc;\nSELECT * FROM automated_report_results WHERE id = 1919;\n\nselect * from automated_report_results WHERE report_id = 54;\n\nselect * from opportunities where id = 7594349;\n\nSELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - jiminnyintegration@lesmills.com\nselect * from playbooks where team_id = 711; # event 226147\nSELECT * FROM playbook_categories WHERE playbook_id = 5515;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';\nSELECT * FROM crm_fields WHERE id = 226147;\nSELECT * FROM crm_field_values WHERE crm_field_id = 226147;\n\nSELECT * FROM crm_configurations WHERE id = 692;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 711 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;\n\nselect * from leads;\n\nselect * from calendars;\n\nSELECT\n t.id AS team_id,\n t.name,\n LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain\nFROM teams t\nJOIN users u ON u.team_id = t.id\nJOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'\nLEFT JOIN team_domains td\n ON td.team_id = t.id\n AND td.deleted_at IS NULL\n AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))\nGROUP BY t.id, t.name, calendar_domain\nORDER BY t.name, calendar_domain;\n\nselect * from users u join calendars c on c.user_id = u.id\nwhere u.team_id = 882;\n\n\nselect * from activities where id = 74049485; # team 563 crm 537\nselect * from activities where id = 73272382; # team 563 crm 537\nselect * from activities where id = 64400389; # team 563 crm 537\nselect * from activities where id = 58081273; # team 563 crm 537\nselect * from activities where id = 54520297; # team 563 crm 537\nselect * from participants where activity_id = 58081273;\n\nselect * from activities where crm_configuration_id = 537 and provider = 'aircall'\nand account_id = 19003658 order by updated_at desc;\n\nselect * from contacts where crm_configuration_id = 537 and id = 35957759;\nselect * from accounts where crm_configuration_id = 537 and id = 19003658;\n\nselect * from automated_report_results where id = 1976;\nselect * from automated_reports where id = 583;\nselect * from activity_searches where id = 87714;\nselect * from activity_search_filters where activity_search_id = 87714;\n\nSELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid\nor uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;\n\nSELECT * FROM crm_configurations WHERE provider = 'hubspot';\nselect * from rate_limits;\n\nselect * from automated_report_results where media_type = 'pdf' and status = 2\nand id IN (18, 1872);\nselect * from automated_reports where id = 54;\nSELECT * FROM users WHERE id IN (24623,29443,29613);\n\nSELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"InviteUserToTeamAction.php, class","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MarkUserAsOnboardableAction.php, class","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncRecordingFlagsAction.php, class","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UpdateTeamMemberAction.php, class","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UpdateUserRolesAction.php, class","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Router","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uploader","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Utility","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Configuration","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Console","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Commands","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activities","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Analytics","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Calendars","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Crm","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Traits","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BackfillOpportunityUserFromAccountCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornCommandAbstract.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornPingCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSearchCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSessionCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CheckActivityLoggableCommand.php, final class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CleanDuplicateFieldDataCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FullSyncOpportunityCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LogActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ManageSyncStrategyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmObjectsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchOpportunityActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MigrateProvider.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProcessHubspotObjectsSyncBatches.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeDeletedOpportunitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ResetGovernorLimits.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SendNotLogged.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupActivityTypeForFollowUp.php, final class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCloseCrm.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCopperCrm.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCrmCommand.php, abstract class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupLayouts.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncAccount.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncContact.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncFieldMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotActiveDeals.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotObjects.php, class","depth":11,"on_screen":false,"role_description":"text"}]...
|
-8010371704475236191
|
2218600140877739847
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
40
1
40
64
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993
SELECT * FROM users WHERE id = 25061;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 994;
SELECT * FROM crm_profiles WHERE user_id = 25061;
select * from crm_configurations where id = 834;
SELECT * FROM teams WHERE id = 882;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;
SELECT * FROM contacts where crm_configuration_id = 834;
SELECT * FROM opportunities WHERE team_id = 933
# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');
AND id IN (8482561,18352941,19042734,19232139,19445140,19472541);
SELECT * FROM opportunity_contacts
WHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 485; #
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
select crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id
where crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')
# and l.converted_at IS NOT NULL
;
# [PASSWORD_DOTS]
SELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')
and opportunity_id IS NULL
order by id desc;
SELECT * FROM teams WHERE id = 604; # 598
SELECT * FROM activities WHERE id = 74410828; # [EMAIL]
SELECT * FROM accounts WHERE id = 20068382;
SELECT * FROM accounts WHERE id = 35186038;
SELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 559 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;
select * from sidekick_settings where team_id = 781;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100
SELECT * FROM crm_layouts WHERE crm_configuration_id = 711;
SELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL
and is_internal = 0 and status = 'completed'
order by id desc;
SELECT * FROM crm_layout_entities
WHERE crm_layout_id IN (2352, 2353);
;
SELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 556 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;
SELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;
select * from contacts
where crm_configuration_id = 530
and crm_provider_id = 872252;
select * from activities where crm_configuration_id = 530
and user_id = 14343 and type like '%softphone%'
and created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);
SELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t
JOIN crm_configurations c ON t.id = c.team_id
WHERE t.status = 'active';
SELECT * FROM teams where id = 1091;
SELECT * FROM crm_configurations where team_id = 1091;
SELECT * FROM activity_providers where team_id = 1091;
SELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT * FROM teams WHERE name LIKE '%Leadventure%';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1091 and sa.provider = 'salesforce';
SELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812
SELECT * FROM teams where id = 862;
SELECT * FROM crm_configurations where team_id = 862;
SELECT * FROM activity_providers where team_id = 862;
SELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT t.id, crm.id, crm.provider, ap.* FROM teams t
join crm_configurations crm on t.id = crm.team_id
join activity_providers ap on t.id = ap.team_id
where t.status = 'active' and ap.is_enabled = 1
and crm.provider = 'hubspot'
and ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',
'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');
SELECT * FROM teams where id = 1068;
SELECT * FROM crm_configurations where team_id = 1068;
SELECT * FROM activity_providers where team_id = 1068;
SELECT * FROM activities a
where crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')
and a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'
)
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by a.id desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1068 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262
SELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
select * from crm_layouts where crm_configuration_id = 834;
select * from crm_layout_entities where crm_layout_id = 2780;
select * from crm_fields where id IN (321153,321192,321193,321194);
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1057 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8
SELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20
SELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10
SELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #
SELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;
select * from users where team_id = 51; # 7783
SELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130
select * from activity_searches where user_id = 7783;
select * from activity_search_filters where activity_search_id IN (32291, 32292);
SELECT asf.activity_search_id, asf.id, asf.value
FROM activity_search_filters asf
WHERE asf.filter = 'group_id'
AND asf.value IN (
SELECT CONCAT(
HEX(SUBSTR(uuid, 5, 4)), '-',
HEX(SUBSTR(uuid, 3, 2)), '-',
HEX(SUBSTR(uuid, 1, 2)), '-',
HEX(SUBSTR(uuid, 9, 2)), '-',
HEX(SUBSTR(uuid, 11))
)
FROM groups
WHERE deleted_at IS NOT NULL
);
SELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where provider = 'hubspot';
SELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133
SELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null
# [PASSWORD_DOTS]
select * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';
select
cp.*
# DISTINCT t.id
# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields
FROM crm_profiles cp
JOIN crm_configurations crm on crm.id = cp.crm_configuration_id
JOIN users u on u.id = cp.user_id
JOIN teams t ON t.id = crm.team_id
WHERE crm.provider = 'salesforce' and t.status = 'active'
and cp.archived_at IS NULL and u.deleted_at IS NULL
and t.id NOT IN (1093)
and t.id = 2
and cp.contact_fields IS NULL;
# and c.crm_provider_id = '003Uu00000ojD4NIAU';
SELECT * FROM users WHERE id = 26484;
SELECT * FROM crm_profiles WHERE user_id = 26484;
SELECT * FROM social_accounts WHERE sociable_id = 26484;
SELECT * FROM crm_configurations where provider = 'salesforce';
select * from users where id IN (10022, 10403);
select * from users where team_id IN (526);
select * from teams where id IN (526, 532);
select * from crm_configurations where id IN (500, 516);
select * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);
select * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 526 and sa.provider = 'salesforce';
select * from team_settings where team_id IN (526, 532);
select * from users where id IN (22824);
select * from crm_profiles where crm_configuration_id IN (1026);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1093 and sa.provider = 'salesforce';
select * from teams where id = 1099;
select * from users where id = 29643
select * from activity_processing_states;
SELECT * FROM teams where name LIKE '%Fare%'; # 233
SELECT * FROM opportunities where crm_configuration_id = 215
# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'
;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1088 and sa.provider = 'hubspot';
SELECT * FROM teams order by updated_at DESC
SELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account
select * from crm_configurations where provider = 'pipedrive';
select * from teams where id = 957;
select * from crm_configurations where id = 957;
SELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743
SELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;
select * from users where team_id = 1; # 26726 - Gabriela Dureva
SELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific
select * from activities where user_id = 26726 order by id desc;
select * from contacts where crm_configuration_id = 1
and email IN ('[EMAIL]', '[EMAIL]'); # 2094416, 2093620
SELECT * FROM contacts WHERE id = 6284931;
SELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id
WHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;
select * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);
select * from crm_configurations where id = 1;
43801692-1aeb-32ce-acba-5b80a479701a
44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b
405975c0-b3d0-7aaa-821f-09d59cae6dd1
4caf848d-4bed-2299-b248-7788d41f9fca
49bedc3f-f196-eef3-89c3-dea6a3b4aa63
43420989-a09d-b8f8-9806-c8bbf7a02aac
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
SELECT * FROM activities WHERE id = 75461988;
SELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;
select * from contacts where id = 17900517;
select * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id
where crm.provider != 'salesforce';
select * from users where id = 21047;
SELECT * FROM crm_configurations WHERE id = 892;
SELECT * FROM teams WHERE id = 942;
select * from opportunities where team_id = 942 order by updated_at desc;
select * from contacts where team_id = 942 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 942 and sa.provider = 'hubspot';
SELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430
SELECT * FROM crm_configurations WHERE id = 1;
SELECT * FROM teams WHERE crm_id = 1;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
select id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1
SELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430
select * from teams where id = 852;
select * from groups where id = 2286;
select * from sidekick_settings where team_id = 852;
select * from default_activity_types where team_id = 852;
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1 AND u.deleted_at IS NULL
AND u.crm_required = 1
AND u.team_id = 1
ORDER BY u.team_id;
SELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (
18481
);
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1
AND u.deleted_at IS NULL
AND u.crm_required = 1
# AND u.team_id = 1
AND p.id IS NULL -- Move this condition to WHERE clause
ORDER BY u.team_id;
SELECT * FROM opportunities WHERE id = 20002609;
select * from teams where id = 1122; # Velatir, 29953 - [EMAIL]
select * from crm_configurations where id = 1060;
select * from crm_layouts where crm_configuration_id = 1060;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1122 and sa.provider = 'hubspot';
select * from opportunities where team_id = 1122 order by updated_at desc;
select * from crm_field_data where object_type = 'contact';
SELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 248 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS
SELECT * FROM users where id = 24115;
SELECT * FROM accounts where id = 4002896;
SELECT * FROM teams WHERE name LIKE '%adswerve%';
SELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN ("0069N000003GIQ9QAO","0061r000019yGP9AAM","0066900001S2KWlAAN","0066900001TDpj2AAD","0066900001b8uEwAAI","0069N000001rQi0QAE","006QF00000KD40mYAD","006QF00000LzpRJYAZ","0069N000002uomtQAA","0069N000002xlMLQAY","0066900001NV6ubAAD","0061r00001HJp45AAD","006QF00000uTlUoYAK","006QF00000v0bZqYAI");
SELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203
SELECT u.id, u.email, ac.name, a.* FROM activities a
JOIN users u ON a.user_id = u.id
JOIN accounts ac ON a.account_id = ac.id
WHERE
uuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or
uuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or
uuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;
select * from users where id = 5825;
SELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;
select * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;
19594, 862
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 862 and sa.provider = 'salesforce';
select * from automated_reports where id = 36;
select ar.frequency, r.*, ar.* from automated_report_results r
join automated_reports ar on r.report_id = ar.id
where ar.frequency != 'one_off';
select s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;
select * from nudges n where n.activity_search_id
select * from teams where created_at > '2026-03-09';
SELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;
select * from users where team_id = 1 and name like '%Lukas%'; # 7160
SELECT * FROM teams WHERE id = 575;
select * from opportunities where team_id = 575;
SELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,
select * from opportunities where team_id = 1126;
SELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,
select * from opportunities where team_id = 1125;
select * from contacts c
where c.team_id = 882;
SELECT * FROM activities WHERE id = 76822967;
SELECT * FROM crm_profiles WHERE user_id = 15440;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 555;
SELECT * FROM crm_configurations WHERE id = 555;
SELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 581 and sa.provider = 'salesforce';
SELECT * FROM automated_report_results order by id desc;
select * from features;
select * from team_features where feature_id = 40;
select * from teams where id = 556;
select * from automated_reports;
where id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , ["pdf","podcast"]
SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;
select * from automated_report_results order by id desc;
SELECT * FROM automated_report_results WHERE id = 1919;
select * from automated_report_results WHERE report_id = 54;
select * from opportunities where id = 7594349;
SELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - [EMAIL]
select * from playbooks where team_id = 711; # event 226147
SELECT * FROM playbook_categories WHERE playbook_id = 5515;
SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';
SELECT * FROM crm_fields WHERE id = 226147;
SELECT * FROM crm_field_values WHERE crm_field_id = 226147;
SELECT * FROM crm_configurations WHERE id = 692;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 711 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;
select * from leads;
select * from calendars;
SELECT
t.id AS team_id,
t.name,
LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain
FROM teams t
JOIN users u ON u.team_id = t.id
JOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'
LEFT JOIN team_domains td
ON td.team_id = t.id
AND td.deleted_at IS NULL
AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))
GROUP BY t.id, t.name, calendar_domain
ORDER BY t.name, calendar_domain;
select * from users u join calendars c on c.user_id = u.id
where u.team_id = 882;
select * from activities where id = 74049485; # team 563 crm 537
select * from activities where id = 73272382; # team 563 crm 537
select * from activities where id = 64400389; # team 563 crm 537
select * from activities where id = 58081273; # team 563 crm 537
select * from activities where id = 54520297; # team 563 crm 537
select * from participants where activity_id = 58081273;
select * from activities where crm_configuration_id = 537 and provider = 'aircall'
and account_id = 19003658 order by updated_at desc;
select * from contacts where crm_configuration_id = 537 and id = 35957759;
select * from accounts where crm_configuration_id = 537 and id = 19003658;
select * from automated_report_results where id = 1976;
select * from automated_reports where id = 583;
select * from activity_searches where id = 87714;
select * from activity_search_filters where activity_search_id = 87714;
SELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid
or uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;
SELECT * FROM crm_configurations WHERE provider = 'hubspot';
select * from rate_limits;
select * from automated_report_results where media_type = 'pdf' and status = 2
and id IN (18, 1872);
select * from automated_reports where id = 54;
SELECT * FROM users WHERE id IN (24623,29443,29613);
SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
InviteUserToTeamAction.php, class
MarkUserAsOnboardableAction.php, class
SyncRecordingFlagsAction.php, class
UpdateTeamMemberAction.php, class
UpdateUserRolesAction.php, class
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot, folder
MobileSettings, folder
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech
PartitionedCookie
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary
Twilio
Uploader
UrlGenerator
Utility
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php
BullhornCommandAbstract.php
BullhornPingCommand.php
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php, final class
CleanDuplicateFieldDataCommand.php, class
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php, class
SetupActivityTypeForFollowUp.php, final class
SetupCloseCrm.php, class
SetupCopperCrm.php, class
SetupCrmCommand.php, abstract class
SetupLayouts.php, class
SyncAccount.php, class
SyncContact.php, class
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class...
|
33553
|
NULL
|
NULL
|
NULL
|
|
33555
|
1274
|
20
|
2026-05-13T10:33:23.580991+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668403580_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzing…","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false}]...
|
-457998036737617651
|
3937494700968608139
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
33556
|
1275
|
21
|
2026-05-13T10:33:23.543380+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668403543_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzing…","depth":4,"bounds":{"left":0.3849734,"top":0.10055866,"width":0.019946808,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","depth":4,"bounds":{"left":0.122340426,"top":0.07661612,"width":0.2855718,"height":0.9233839},"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false}]...
|
-457998036737617651
|
3937494700968608139
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
33557
|
1274
|
21
|
2026-05-13T10:33:25.536915+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668405536_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4235983745889776938
|
-8204421443435123770
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
QuickTime PlayerFileEditViewWindowHelpGalya Dimitrova (Presenting, annotating)SlackFileEditViewGoHistoryWindowHelp÷88JIMg For you• Recent [# Starred°? Apps|& Plans0 SpacesStarredJiminny (New)|u Platform TelIID ProcessingUID SE KanbanIID Capture TeaU Enterprise 9DiscoveryDMs+ActivityFiesLaterMoreProductRecent(9 Service-Desk= More spaces= FiltersB DashboardsOperations& CustomersJiminny Inc~+ More unread messagesE Lukas Kovalik, Nikolay..C. Nikolay IvanovP. Nikolay Yankov. Petko Kashinski. Stefka Stoyanovad Stoyan Tanev. Vasil Vasilev ER. Vilma A(. ZoriAP. Galya Dimitrova...Channels# alertsAppsConfluenceGoogle CalendarGoogle DrivejiminnyJira CloudToastu UserpilotQ Describe what you are looking for# alerts8 22| MessagesAdd canvasO Filesmyana neeseva 1uzyhas been added to #alerts by Mira.Monday, 6 April -Thursday, 9 AprilAutomation for Jira APPSRD-6782 Transcription issue has been escalated with Critical priority to" @hereAutomation for Jira APPSRD:6782 Transcription issue has been assigned with Critical priority to Mihail Mihaylov @hereToday ~CircleCl APP 10:122 PRs with vulnerability fixes are ready for review $Please take a look at the code and confirm that everything works properly on your local machine oron a planet environment jPull requests (Gjiminny/app)• $11970 fix/securitvl.composer dependensyundates - 2026-04-15 (secfix/composer-20260415)• $11969 fix/securitvl.nom denendensy_undates - 2026-04-15 (secfix/npm-20260415 )|View workflow.rvn$ 1Message #alertsAa@JY-19967 Upgrade Python and libraries - AprMAINTENANCEBACKLOG v+ Createmeet.9o09e.com is snaring your SorcenStop sharingClick or hold page_up + page_down to start dictating(alol# Support Daily - in 1 h 27 m1428• Wed 15 Apr 10:37Campus X|) FirebaseE UM EvalunAsk Rovo4ComponentsMore 9+4.5= 8== 8= &= &= *= *= 8= 8= 8= %= 8=10:37 AM | [Platform] Planning | Session i7100% <8• Wed 13 May 13:33:259000Nikolay NikolovGalya Dimitrova4 othersStefka StoyanovaLukas Kovalik...
|
33555
|
NULL
|
NULL
|
NULL
|
|
33558
|
1274
|
22
|
2026-05-13T10:33:27.130022+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668407130_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
40
1
40
64
Previous Highlighted Error
Next Highlighted Error...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzing…","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"40","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"40","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"64","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8505636593219184387
|
-7591861084844750069
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
40
1
40
64
Previous Highlighted Error
Next Highlighted Error...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
33559
|
1275
|
22
|
2026-05-13T10:33:26.080648+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668406080_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4047408223668449518
|
-8636777727364969024
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
PhostormINavigareCodeLaravelKeractorWindowFV faVsco.js?9 master kProiect(C) DetaultProspectSearciMallooxcontroller.pnp© EmailHelper.php(1) FindsProspectintertacAnalyzing...namespace Jininny services Mall© LayoutManager.php(0 MatchDomainRvEmailuse...© OpportunityActivityMa© OpportunitySyncStrateclass TextrelayServicec Opportunitysynestrale© ProspectCache.php© ProspectSearchScope© ProspectSearchStrateu Prospectsearchstratec)Providerkeoistrv.onoRecordSelector.php( ResolveCompanvNamC) TimePeriodIterator.ohrImporiInternallKioskv AutomatedRenortsC) ActivitvtvoeServicC) Ask liminnvReportAC) AutomatedRenortsiC) AutomatedRenortsC) DealStadesServicec) RecinienteService re) RenortSort nhr€ ReportSortDirectior(C) KiockService nhnv M Mail)MActioncmaffino> @ RepositoriesM Docalvore>C TraitsM Validators(e) RatchCriteria.pho* BatchCriterialnterface© BatchService.php@ BatchServicelnterfaceC)EmaillActivivService.oEmailActivitvServicelniC) [EMAIL]@ InboyServicelnterface(1) InternetMessagelnterf(c) Mailchanne Service oi© TextRelayService.php1M MeptinaGenerato> M Notificationpublic function __construct(){...}* Fetch the latest messages since the last sunclpublic function sync): arraySmailbox = config('jiminny.google_text_user');Sservice = $this->getService($mailbox):SmessageHistory = Sthis->getHistory(Sservice):SmessageIds = 0]:foreach (SmessageHistory as $histories) {Smessages = Shistories->messagesAdded:toreach (Smessages as Smessage "SmessageId = Smessage->message->id:SrelayedText = TextRelay::where('email provider id' Smessageld)->firstO:if (SrelayedText === null) {srelavedllext = lextrelav::createu'email provider' => TextRelav:: PROVIDER GSUITE..'email_provider_id' => Smessageld,'status' => TextRelav:: STATUS PROCESSING.Sioh = (new EmailTextRelav(Smessageld. SrelavedTeyt))->onQueue(Constants:•OUFUE EMATLS)!disnatch(Siob)SmessaaeTdsil = Smessaaeld.notunn CmoccanoTde.public function getHistory(GoogleGmail Sservice): array{...}protected function setHistoryPoint(string Stopic, int $historyPoint): Carbon{...}er' hac heon rectored Il Pollback II Confiaure (56 minutes aao)=laravel.logA SF (jiminny@localhost]4 HS_local [jiminny@localhost]& console (PROD] X A console [EU]A console [STAGING] Tx: Auto vSELECT * FROM crm_configurations WHERE id = 555;SELE * FROM users WHERE 1d = 15440: # team. 581, or. 15440. pl. 3911, act. Field 162182So jiminny40 41 440 X.04CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,sa.*t.owner_id FROM social_accounts saJOTN usens u on u.id = sa.sociable idlJOIN teams t 1.n<->1: on t.id = u.team_ioWHERE u.team_id = 581 and sa.provider = 'salesforce';SELECT * FROM automated report results order by id desc:select * from features;select * from team_features where feature_id = 40;select * from teams where id = 556:select * from automated reports:where id = 54; # 4Fdd41f6-dcF0-30d0-b339-7345381b6044["pdf", "podcast"]SELECT * FROM automated report results WHERE uuid to bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid:automated report results order by 1d descSELEC * FROM automated report results WHERE 10 = 1919select * from automated_report_results WHERE report id = 54;select * from onnortunities where id = 7594349:SELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 -[EMAIL] * from playbooks where team_id = 711; # event 226147SELECT * FROM playbook_categories WHERE playbook_id = 5515;SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';SELECT * CP0M eom fiolde WHERE id = 226147•SELECT * FROM crm_field_values WHERE crm_field_id = 226147;SELECT * FROM crm_configurations WHERE id = 692;SELSCTCONCAT(u.id, CASE WHEN u.id = t.owner id THEN ' (owner)' ELSE '• END) AS user id.momosalsa.*,t.owner_id FROM social_accounts saJOIN users u on u.id = sa.sociable_idLIOTM toome + 1 ne-df. on + ¿d = n +oom ¿dlWHERE u.team_id = 711 and sa.provider = 'salesforce':SELECT * FROM crm profiles co JOTN users u 1.n<->1: on u.id = co.user id WHERE u.team_id = 711:select * from leads:cascadeTrial Owner Role Sele• suppont Dally • In 1h 21m100% L2• Wed 13 May 13:33:25AskJiminnyReportActivityServiceTest -SMS Failure Email Inve+0 ..Access to file . env is prohibited by .aitiqnore. You can enable access to gitignore files by enabling the setting Allow cascdde access to breignore ritesRead api.php #L1-610Searched GOOGLE_TEXT_RELAY in ~/jiminny/appComplete SMS Email-to-Text Relay Flow1. Trigger PointRoute: POST aoi/sms/relay lin routes/aot, oho line 121 trom webhook.oho) controller: Mar looxcontro ler:: relavo(lines 27-38)D phppublic Tunction relay: kesponsetry{Sthis->relayService->sync():} catch (\Exception $e) (\Sentry:: captureException(Se):throw se:2, Email Svnc (TextRelavService::svnco))• Fetches Gmail history since last sync point (cached)• Creates TextRelay records with STATUS PROCESSING• Dispatches EmailTextRelay jobs for each new email3. Job Processing (EmailTextRelay::handle())Lines 79-159:Anhotry {// 1. Retrieve email from GmailSmessage = Sthis->aetMessade Smal Service, Sthis->message1d):// 2. Extract headers and bodys->getHeaders (Spayload->getHeaders());Sbody = Sthis->getBodySpayload->qetPartso):1/ 2. Validate intearity (checkIntearitv)Ask anvthina (84L)« Code SWF-1.6WN Windsurf Teams24-20 LTF.Rio 4 spaces...
|
33556
|
NULL
|
NULL
|
NULL
|
|
33560
|
1274
|
23
|
2026-05-13T10:33:30.971079+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668410971_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
40
1
40
64
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993
SELECT * FROM users WHERE id = 25061;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 994;
SELECT * FROM crm_profiles WHERE user_id = 25061;
select * from crm_configurations where id = 834;
SELECT * FROM teams WHERE id = 882;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;
SELECT * FROM contacts where crm_configuration_id = 834;
SELECT * FROM opportunities WHERE team_id = 933
# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');
AND id IN (8482561,18352941,19042734,19232139,19445140,19472541);
SELECT * FROM opportunity_contacts
WHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 485; #
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
select crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id
where crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')
# and l.converted_at IS NOT NULL
;
# [PASSWORD_DOTS]
SELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')
and opportunity_id IS NULL
order by id desc;
SELECT * FROM teams WHERE id = 604; # 598
SELECT * FROM activities WHERE id = 74410828; # [EMAIL]
SELECT * FROM accounts WHERE id = 20068382;
SELECT * FROM accounts WHERE id = 35186038;
SELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 559 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;
select * from sidekick_settings where team_id = 781;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100
SELECT * FROM crm_layouts WHERE crm_configuration_id = 711;
SELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL
and is_internal = 0 and status = 'completed'
order by id desc;
SELECT * FROM crm_layout_entities
WHERE crm_layout_id IN (2352, 2353);
;
SELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 556 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;
SELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;
select * from contacts
where crm_configuration_id = 530
and crm_provider_id = 872252;
select * from activities where crm_configuration_id = 530
and user_id = 14343 and type like '%softphone%'
and created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);
SELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t
JOIN crm_configurations c ON t.id = c.team_id
WHERE t.status = 'active';
SELECT * FROM teams where id = 1091;
SELECT * FROM crm_configurations where team_id = 1091;
SELECT * FROM activity_providers where team_id = 1091;
SELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT * FROM teams WHERE name LIKE '%Leadventure%';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1091 and sa.provider = 'salesforce';
SELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812
SELECT * FROM teams where id = 862;
SELECT * FROM crm_configurations where team_id = 862;
SELECT * FROM activity_providers where team_id = 862;
SELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT t.id, crm.id, crm.provider, ap.* FROM teams t
join crm_configurations crm on t.id = crm.team_id
join activity_providers ap on t.id = ap.team_id
where t.status = 'active' and ap.is_enabled = 1
and crm.provider = 'hubspot'
and ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',
'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');
SELECT * FROM teams where id = 1068;
SELECT * FROM crm_configurations where team_id = 1068;
SELECT * FROM activity_providers where team_id = 1068;
SELECT * FROM activities a
where crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')
and a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'
)
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by a.id desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1068 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262
SELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
select * from crm_layouts where crm_configuration_id = 834;
select * from crm_layout_entities where crm_layout_id = 2780;
select * from crm_fields where id IN (321153,321192,321193,321194);
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1057 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8
SELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20
SELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10
SELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #
SELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;
select * from users where team_id = 51; # 7783
SELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130
select * from activity_searches where user_id = 7783;
select * from activity_search_filters where activity_search_id IN (32291, 32292);
SELECT asf.activity_search_id, asf.id, asf.value
FROM activity_search_filters asf
WHERE asf.filter = 'group_id'
AND asf.value IN (
SELECT CONCAT(
HEX(SUBSTR(uuid, 5, 4)), '-',
HEX(SUBSTR(uuid, 3, 2)), '-',
HEX(SUBSTR(uuid, 1, 2)), '-',
HEX(SUBSTR(uuid, 9, 2)), '-',
HEX(SUBSTR(uuid, 11))
)
FROM groups
WHERE deleted_at IS NOT NULL
);
SELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where provider = 'hubspot';
SELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133
SELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null
# [PASSWORD_DOTS]
select * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';
select
cp.*
# DISTINCT t.id
# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields
FROM crm_profiles cp
JOIN crm_configurations crm on crm.id = cp.crm_configuration_id
JOIN users u on u.id = cp.user_id
JOIN teams t ON t.id = crm.team_id
WHERE crm.provider = 'salesforce' and t.status = 'active'
and cp.archived_at IS NULL and u.deleted_at IS NULL
and t.id NOT IN (1093)
and t.id = 2
and cp.contact_fields IS NULL;
# and c.crm_provider_id = '003Uu00000ojD4NIAU';
SELECT * FROM users WHERE id = 26484;
SELECT * FROM crm_profiles WHERE user_id = 26484;
SELECT * FROM social_accounts WHERE sociable_id = 26484;
SELECT * FROM crm_configurations where provider = 'salesforce';
select * from users where id IN (10022, 10403);
select * from users where team_id IN (526);
select * from teams where id IN (526, 532);
select * from crm_configurations where id IN (500, 516);
select * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);
select * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 526 and sa.provider = 'salesforce';
select * from team_settings where team_id IN (526, 532);
select * from users where id IN (22824);
select * from crm_profiles where crm_configuration_id IN (1026);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1093 and sa.provider = 'salesforce';
select * from teams where id = 1099;
select * from users where id = 29643
select * from activity_processing_states;
SELECT * FROM teams where name LIKE '%Fare%'; # 233
SELECT * FROM opportunities where crm_configuration_id = 215
# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'
;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1088 and sa.provider = 'hubspot';
SELECT * FROM teams order by updated_at DESC
SELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account
select * from crm_configurations where provider = 'pipedrive';
select * from teams where id = 957;
select * from crm_configurations where id = 957;
SELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743
SELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;
select * from users where team_id = 1; # 26726 - Gabriela Dureva
SELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific
select * from activities where user_id = 26726 order by id desc;
select * from contacts where crm_configuration_id = 1
and email IN ('[EMAIL]', '[EMAIL]'); # 2094416, 2093620
SELECT * FROM contacts WHERE id = 6284931;
SELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id
WHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;
select * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);
select * from crm_configurations where id = 1;
43801692-1aeb-32ce-acba-5b80a479701a
44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b
405975c0-b3d0-7aaa-821f-09d59cae6dd1
4caf848d-4bed-2299-b248-7788d41f9fca
49bedc3f-f196-eef3-89c3-dea6a3b4aa63
43420989-a09d-b8f8-9806-c8bbf7a02aac
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
SELECT * FROM activities WHERE id = 75461988;
SELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;
select * from contacts where id = 17900517;
select * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id
where crm.provider != 'salesforce';
select * from users where id = 21047;
SELECT * FROM crm_configurations WHERE id = 892;
SELECT * FROM teams WHERE id = 942;
select * from opportunities where team_id = 942 order by updated_at desc;
select * from contacts where team_id = 942 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 942 and sa.provider = 'hubspot';
SELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430
SELECT * FROM crm_configurations WHERE id = 1;
SELECT * FROM teams WHERE crm_id = 1;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
select id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1
SELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430
select * from teams where id = 852;
select * from groups where id = 2286;
select * from sidekick_settings where team_id = 852;
select * from default_activity_types where team_id = 852;
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1 AND u.deleted_at IS NULL
AND u.crm_required = 1
AND u.team_id = 1
ORDER BY u.team_id;
SELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (
18481
);
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1
AND u.deleted_at IS NULL
AND u.crm_required = 1
# AND u.team_id = 1
AND p.id IS NULL -- Move this condition to WHERE clause
ORDER BY u.team_id;
SELECT * FROM opportunities WHERE id = 20002609;
select * from teams where id = 1122; # Velatir, 29953 - [EMAIL]
select * from crm_configurations where id = 1060;
select * from crm_layouts where crm_configuration_id = 1060;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1122 and sa.provider = 'hubspot';
select * from opportunities where team_id = 1122 order by updated_at desc;
select * from crm_field_data where object_type = 'contact';
SELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 248 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS
SELECT * FROM users where id = 24115;
SELECT * FROM accounts where id = 4002896;
SELECT * FROM teams WHERE name LIKE '%adswerve%';
SELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN ("0069N000003GIQ9QAO","0061r000019yGP9AAM","0066900001S2KWlAAN","0066900001TDpj2AAD","0066900001b8uEwAAI","0069N000001rQi0QAE","006QF00000KD40mYAD","006QF00000LzpRJYAZ","0069N000002uomtQAA","0069N000002xlMLQAY","0066900001NV6ubAAD","0061r00001HJp45AAD","006QF00000uTlUoYAK","006QF00000v0bZqYAI");
SELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203
SELECT u.id, u.email, ac.name, a.* FROM activities a
JOIN users u ON a.user_id = u.id
JOIN accounts ac ON a.account_id = ac.id
WHERE
uuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or
uuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or
uuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;
select * from users where id = 5825;
SELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;
select * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;
19594, 862
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 862 and sa.provider = 'salesforce';
select * from automated_reports where id = 36;
select ar.frequency, r.*, ar.* from automated_report_results r
join automated_reports ar on r.report_id = ar.id
where ar.frequency != 'one_off';
select s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;
select * from nudges n where n.activity_search_id
select * from teams where created_at > '2026-03-09';
SELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;
select * from users where team_id = 1 and name like '%Lukas%'; # 7160
SELECT * FROM teams WHERE id = 575;
select * from opportunities where team_id = 575;
SELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,
select * from opportunities where team_id = 1126;
SELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,
select * from opportunities where team_id = 1125;
select * from contacts c
where c.team_id = 882;
SELECT * FROM activities WHERE id = 76822967;
SELECT * FROM crm_profiles WHERE user_id = 15440;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 555;
SELECT * FROM crm_configurations WHERE id = 555;
SELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 581 and sa.provider = 'salesforce';
SELECT * FROM automated_report_results order by id desc;
select * from features;
select * from team_features where feature_id = 40;
select * from teams where id = 556;
select * from automated_reports;
where id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , ["pdf","podcast"]
SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;
select * from automated_report_results order by id desc;
SELECT * FROM automated_report_results WHERE id = 1919;
select * from automated_report_results WHERE report_id = 54;
select * from opportunities where id = 7594349;
SELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - [EMAIL]
select * from playbooks where team_id = 711; # event 226147
SELECT * FROM playbook_categories WHERE playbook_id = 5515;
SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';
SELECT * FROM crm_fields WHERE id = 226147;
SELECT * FROM crm_field_values WHERE crm_field_id = 226147;
SELECT * FROM crm_configurations WHERE id = 692;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 711 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;
select * from leads;
select * from calendars;
SELECT
t.id AS team_id,
t.name,
LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain
FROM teams t
JOIN users u ON u.team_id = t.id
JOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'
LEFT JOIN team_domains td
ON td.team_id = t.id
AND td.deleted_at IS NULL
AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))
GROUP BY t.id, t.name, calendar_domain
ORDER BY t.name, calendar_domain;
select * from users u join calendars c on c.user_id = u.id
where u.team_id = 882;
select * from activities where id = 74049485; # team 563 crm 537
select * from activities where id = 73272382; # team 563 crm 537
select * from activities where id = 64400389; # team 563 crm 537
select * from activities where id = 58081273; # team 563 crm 537
select * from activities where id = 54520297; # team 563 crm 537
select * from participants where activity_id = 58081273;
select * from activities where crm_configuration_id = 537 and provider = 'aircall'
and account_id = 19003658 order by updated_at desc;
select * from contacts where crm_configuration_id = 537 and id = 35957759;
select * from accounts where crm_configuration_id = 537 and id = 19003658;
select * from automated_report_results where id = 1976;
select * from automated_reports where id = 583;
select * from activity_searches where id = 87714;
select * from activity_search_filters where activity_search_id = 87714;
SELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid
or uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;
SELECT * FROM crm_configurations WHERE provider = 'hubspot';
select * from rate_limits;
select * from automated_report_results where media_type = 'pdf' and status = 2
and id IN (18, 1872);
select * from automated_reports where id = 54;
SELECT * FROM users WHERE id IN (24623,29443,29613);
SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzing…","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"40","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"40","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"64","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993\nSELECT * FROM users WHERE id = 25061;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 994;\nSELECT * FROM crm_profiles WHERE user_id = 25061;\n\nselect * from crm_configurations where id = 834;\nSELECT * FROM teams WHERE id = 882;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;\n\nSELECT * FROM contacts where crm_configuration_id = 834;\nSELECT * FROM opportunities WHERE team_id = 933\n# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');\nAND id IN (8482561,18352941,19042734,19232139,19445140,19472541);\nSELECT * FROM opportunity_contacts\nWHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 485; #\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nselect crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id\nwhere crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')\n# and l.converted_at IS NOT NULL\n;\n\n# ********************************************************************\nSELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')\nand opportunity_id IS NULL\norder by id desc;\n\nSELECT * FROM teams WHERE id = 604; # 598\nSELECT * FROM activities WHERE id = 74410828; # chelseaw@allvoices.co\nSELECT * FROM accounts WHERE id = 20068382;\nSELECT * FROM accounts WHERE id = 35186038;\n\nSELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 559 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;\nselect * from sidekick_settings where team_id = 781;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100\n\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 711;\nSELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL\nand is_internal = 0 and status = 'completed'\norder by id desc;\n\nSELECT * FROM crm_layout_entities\nWHERE crm_layout_id IN (2352, 2353);\n;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 556 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;\nSELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;\nselect * from contacts\nwhere crm_configuration_id = 530\nand crm_provider_id = 872252;\n\nselect * from activities where crm_configuration_id = 530\nand user_id = 14343 and type like '%softphone%'\nand created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);\n\n\nSELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t\nJOIN crm_configurations c ON t.id = c.team_id\nWHERE t.status = 'active';\n\nSELECT * FROM teams where id = 1091;\nSELECT * FROM crm_configurations where team_id = 1091;\nSELECT * FROM activity_providers where team_id = 1091;\nSELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT * FROM teams WHERE name LIKE '%Leadventure%';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1091 and sa.provider = 'salesforce';\n\nSELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812\nSELECT * FROM teams where id = 862;\nSELECT * FROM crm_configurations where team_id = 862;\nSELECT * FROM activity_providers where team_id = 862;\nSELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT t.id, crm.id, crm.provider, ap.* FROM teams t\njoin crm_configurations crm on t.id = crm.team_id\njoin activity_providers ap on t.id = ap.team_id\nwhere t.status = 'active' and ap.is_enabled = 1\nand crm.provider = 'hubspot'\nand ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',\n 'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');\n\nSELECT * FROM teams where id = 1068;\nSELECT * FROM crm_configurations where team_id = 1068;\nSELECT * FROM activity_providers where team_id = 1068;\n\nSELECT * FROM activities a\nwhere crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')\nand a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'\n )\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by a.id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1068 and sa.provider = 'hubspot';\n\n# ********************************************************************\n# ********************************************************************\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262\nSELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\nselect * from crm_layouts where crm_configuration_id = 834;\nselect * from crm_layout_entities where crm_layout_id = 2780;\nselect * from crm_fields where id IN (321153,321192,321193,321194);\n\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1057 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8\n\nSELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20\n\nSELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10\n\nSELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #\n\nSELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;\nselect * from users where team_id = 51; # 7783\nSELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130\nselect * from activity_searches where user_id = 7783;\nselect * from activity_search_filters where activity_search_id IN (32291, 32292);\n\nSELECT asf.activity_search_id, asf.id, asf.value\nFROM activity_search_filters asf\nWHERE asf.filter = 'group_id'\nAND asf.value IN (\n SELECT CONCAT(\n HEX(SUBSTR(uuid, 5, 4)), '-',\n HEX(SUBSTR(uuid, 3, 2)), '-',\n HEX(SUBSTR(uuid, 1, 2)), '-',\n HEX(SUBSTR(uuid, 9, 2)), '-',\n HEX(SUBSTR(uuid, 11))\n )\n FROM groups\n WHERE deleted_at IS NOT NULL\n);\n\nSELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th\n# ********************************************************************\nSELECT * FROM crm_configurations where provider = 'hubspot';\nSELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133\nSELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null\n# ********************************************************************\n\nselect * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';\nselect\n cp.*\n# DISTINCT t.id\n# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields\nFROM crm_profiles cp\nJOIN crm_configurations crm on crm.id = cp.crm_configuration_id\nJOIN users u on u.id = cp.user_id\nJOIN teams t ON t.id = crm.team_id\nWHERE crm.provider = 'salesforce' and t.status = 'active'\n and cp.archived_at IS NULL and u.deleted_at IS NULL\n and t.id NOT IN (1093)\n and t.id = 2\n and cp.contact_fields IS NULL;\n# and c.crm_provider_id = '003Uu00000ojD4NIAU';\n\nSELECT * FROM users WHERE id = 26484;\nSELECT * FROM crm_profiles WHERE user_id = 26484;\nSELECT * FROM social_accounts WHERE sociable_id = 26484;\nSELECT * FROM crm_configurations where provider = 'salesforce';\nselect * from users where id IN (10022, 10403);\nselect * from users where team_id IN (526);\nselect * from teams where id IN (526, 532);\nselect * from crm_configurations where id IN (500, 516);\nselect * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);\nselect * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 526 and sa.provider = 'salesforce';\nselect * from team_settings where team_id IN (526, 532);\n\nselect * from users where id IN (22824);\nselect * from crm_profiles where crm_configuration_id IN (1026);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1093 and sa.provider = 'salesforce';\n\nselect * from teams where id = 1099;\nselect * from users where id = 29643\n\nselect * from activity_processing_states;\n\nSELECT * FROM teams where name LIKE '%Fare%'; # 233\nSELECT * FROM opportunities where crm_configuration_id = 215\n# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'\n;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1088 and sa.provider = 'hubspot';\n\nSELECT * FROM teams order by updated_at DESC\nSELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account\n\nselect * from crm_configurations where provider = 'pipedrive';\n\nselect * from teams where id = 957;\nselect * from crm_configurations where id = 957;\n\nSELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743\nSELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;\n\nselect * from users where team_id = 1; # 26726 - Gabriela Dureva\nSELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific\nselect * from activities where user_id = 26726 order by id desc;\nselect * from contacts where crm_configuration_id = 1\nand email IN ('charlotte.ward@prolific.com', 'frankie.bryant@prolific.com'); # 2094416, 2093620\nSELECT * FROM contacts WHERE id = 6284931;\n\nSELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id\nWHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;\n\nselect * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);\nselect * from crm_configurations where id = 1;\n\n43801692-1aeb-32ce-acba-5b80a479701a\n44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b\n405975c0-b3d0-7aaa-821f-09d59cae6dd1\n4caf848d-4bed-2299-b248-7788d41f9fca\n49bedc3f-f196-eef3-89c3-dea6a3b4aa63\n43420989-a09d-b8f8-9806-c8bbf7a02aac\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nSELECT * FROM activities WHERE id = 75461988;\n\nSELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;\n\nselect * from contacts where id = 17900517;\n\nselect * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id\nwhere crm.provider != 'salesforce';\n\nselect * from users where id = 21047;\nSELECT * FROM crm_configurations WHERE id = 892;\nSELECT * FROM teams WHERE id = 942;\nselect * from opportunities where team_id = 942 order by updated_at desc;\nselect * from contacts where team_id = 942 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 942 and sa.provider = 'hubspot';\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430\nSELECT * FROM crm_configurations WHERE id = 1;\nSELECT * FROM teams WHERE crm_id = 1;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nselect id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1\nSELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430\n\nselect * from teams where id = 852;\nselect * from groups where id = 2286;\nselect * from sidekick_settings where team_id = 852;\nselect * from default_activity_types where team_id = 852;\n\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1 AND u.deleted_at IS NULL\nAND u.crm_required = 1\nAND u.team_id = 1\nORDER BY u.team_id;\n\nSELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (\n18481\n );\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1\n AND u.deleted_at IS NULL\n AND u.crm_required = 1\n# AND u.team_id = 1\n AND p.id IS NULL -- Move this condition to WHERE clause\nORDER BY u.team_id;\n\nSELECT * FROM opportunities WHERE id = 20002609;\nselect * from teams where id = 1122; # Velatir, 29953 - christian@velatir.com\nselect * from crm_configurations where id = 1060;\nselect * from crm_layouts where crm_configuration_id = 1060;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1122 and sa.provider = 'hubspot';\nselect * from opportunities where team_id = 1122 order by updated_at desc;\n\nselect * from crm_field_data where object_type = 'contact';\n\nSELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 248 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS\nSELECT * FROM users where id = 24115;\nSELECT * FROM accounts where id = 4002896;\nSELECT * FROM teams WHERE name LIKE '%adswerve%';\nSELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN (\"0069N000003GIQ9QAO\",\"0061r000019yGP9AAM\",\"0066900001S2KWlAAN\",\"0066900001TDpj2AAD\",\"0066900001b8uEwAAI\",\"0069N000001rQi0QAE\",\"006QF00000KD40mYAD\",\"006QF00000LzpRJYAZ\",\"0069N000002uomtQAA\",\"0069N000002xlMLQAY\",\"0066900001NV6ubAAD\",\"0061r00001HJp45AAD\",\"006QF00000uTlUoYAK\",\"006QF00000v0bZqYAI\");\nSELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203\n\nSELECT u.id, u.email, ac.name, a.* FROM activities a\nJOIN users u ON a.user_id = u.id\nJOIN accounts ac ON a.account_id = ac.id\nWHERE\nuuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or\nuuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or\nuuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;\n\nselect * from users where id = 5825;\nSELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;\n\nselect * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;\n19594, 862\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 862 and sa.provider = 'salesforce';\n\nselect * from automated_reports where id = 36;\nselect ar.frequency, r.*, ar.* from automated_report_results r\njoin automated_reports ar on r.report_id = ar.id\nwhere ar.frequency != 'one_off';\n\nselect s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;\nselect * from nudges n where n.activity_search_id\n\nselect * from teams where created_at > '2026-03-09';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;\n\nselect * from users where team_id = 1 and name like '%Lukas%'; # 7160\n\nSELECT * FROM teams WHERE id = 575;\nselect * from opportunities where team_id = 575;\nSELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,\nselect * from opportunities where team_id = 1126;\nSELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,\nselect * from opportunities where team_id = 1125;\nselect * from contacts c\nwhere c.team_id = 882;\n\nSELECT * FROM activities WHERE id = 76822967;\nSELECT * FROM crm_profiles WHERE user_id = 15440;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 555;\nSELECT * FROM crm_configurations WHERE id = 555;\nSELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 581 and sa.provider = 'salesforce';\n\nSELECT * FROM automated_report_results order by id desc;\n\nselect * from features;\nselect * from team_features where feature_id = 40;\n\nselect * from teams where id = 556;\n\nselect * from automated_reports;\nwhere id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , [\"pdf\",\"podcast\"]\nSELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;\nselect * from automated_report_results order by id desc;\nSELECT * FROM automated_report_results WHERE id = 1919;\n\nselect * from automated_report_results WHERE report_id = 54;\n\nselect * from opportunities where id = 7594349;\n\nSELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - jiminnyintegration@lesmills.com\nselect * from playbooks where team_id = 711; # event 226147\nSELECT * FROM playbook_categories WHERE playbook_id = 5515;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';\nSELECT * FROM crm_fields WHERE id = 226147;\nSELECT * FROM crm_field_values WHERE crm_field_id = 226147;\n\nSELECT * FROM crm_configurations WHERE id = 692;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 711 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;\n\nselect * from leads;\n\nselect * from calendars;\n\nSELECT\n t.id AS team_id,\n t.name,\n LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain\nFROM teams t\nJOIN users u ON u.team_id = t.id\nJOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'\nLEFT JOIN team_domains td\n ON td.team_id = t.id\n AND td.deleted_at IS NULL\n AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))\nGROUP BY t.id, t.name, calendar_domain\nORDER BY t.name, calendar_domain;\n\nselect * from users u join calendars c on c.user_id = u.id\nwhere u.team_id = 882;\n\n\nselect * from activities where id = 74049485; # team 563 crm 537\nselect * from activities where id = 73272382; # team 563 crm 537\nselect * from activities where id = 64400389; # team 563 crm 537\nselect * from activities where id = 58081273; # team 563 crm 537\nselect * from activities where id = 54520297; # team 563 crm 537\nselect * from participants where activity_id = 58081273;\n\nselect * from activities where crm_configuration_id = 537 and provider = 'aircall'\nand account_id = 19003658 order by updated_at desc;\n\nselect * from contacts where crm_configuration_id = 537 and id = 35957759;\nselect * from accounts where crm_configuration_id = 537 and id = 19003658;\n\nselect * from automated_report_results where id = 1976;\nselect * from automated_reports where id = 583;\nselect * from activity_searches where id = 87714;\nselect * from activity_search_filters where activity_search_id = 87714;\n\nSELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid\nor uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;\n\nSELECT * FROM crm_configurations WHERE provider = 'hubspot';\nselect * from rate_limits;\n\nselect * from automated_report_results where media_type = 'pdf' and status = 2\nand id IN (18, 1872);\nselect * from automated_reports where id = 54;\nSELECT * FROM users WHERE id IN (24623,29443,29613);\n\nSELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;","depth":4,"on_screen":true,"value":"SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993\nSELECT * FROM users WHERE id = 25061;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 994;\nSELECT * FROM crm_profiles WHERE user_id = 25061;\n\nselect * from crm_configurations where id = 834;\nSELECT * FROM teams WHERE id = 882;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;\n\nSELECT * FROM contacts where crm_configuration_id = 834;\nSELECT * FROM opportunities WHERE team_id = 933\n# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');\nAND id IN (8482561,18352941,19042734,19232139,19445140,19472541);\nSELECT * FROM opportunity_contacts\nWHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 485; #\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nselect crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id\nwhere crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')\n# and l.converted_at IS NOT NULL\n;\n\n# ********************************************************************\nSELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')\nand opportunity_id IS NULL\norder by id desc;\n\nSELECT * FROM teams WHERE id = 604; # 598\nSELECT * FROM activities WHERE id = 74410828; # chelseaw@allvoices.co\nSELECT * FROM accounts WHERE id = 20068382;\nSELECT * FROM accounts WHERE id = 35186038;\n\nSELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 559 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;\nselect * from sidekick_settings where team_id = 781;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100\n\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 711;\nSELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL\nand is_internal = 0 and status = 'completed'\norder by id desc;\n\nSELECT * FROM crm_layout_entities\nWHERE crm_layout_id IN (2352, 2353);\n;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 556 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;\nSELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;\nselect * from contacts\nwhere crm_configuration_id = 530\nand crm_provider_id = 872252;\n\nselect * from activities where crm_configuration_id = 530\nand user_id = 14343 and type like '%softphone%'\nand created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);\n\n\nSELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t\nJOIN crm_configurations c ON t.id = c.team_id\nWHERE t.status = 'active';\n\nSELECT * FROM teams where id = 1091;\nSELECT * FROM crm_configurations where team_id = 1091;\nSELECT * FROM activity_providers where team_id = 1091;\nSELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT * FROM teams WHERE name LIKE '%Leadventure%';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1091 and sa.provider = 'salesforce';\n\nSELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812\nSELECT * FROM teams where id = 862;\nSELECT * FROM crm_configurations where team_id = 862;\nSELECT * FROM activity_providers where team_id = 862;\nSELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT t.id, crm.id, crm.provider, ap.* FROM teams t\njoin crm_configurations crm on t.id = crm.team_id\njoin activity_providers ap on t.id = ap.team_id\nwhere t.status = 'active' and ap.is_enabled = 1\nand crm.provider = 'hubspot'\nand ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',\n 'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');\n\nSELECT * FROM teams where id = 1068;\nSELECT * FROM crm_configurations where team_id = 1068;\nSELECT * FROM activity_providers where team_id = 1068;\n\nSELECT * FROM activities a\nwhere crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')\nand a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'\n )\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by a.id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1068 and sa.provider = 'hubspot';\n\n# ********************************************************************\n# ********************************************************************\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262\nSELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\nselect * from crm_layouts where crm_configuration_id = 834;\nselect * from crm_layout_entities where crm_layout_id = 2780;\nselect * from crm_fields where id IN (321153,321192,321193,321194);\n\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1057 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8\n\nSELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20\n\nSELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10\n\nSELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #\n\nSELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;\nselect * from users where team_id = 51; # 7783\nSELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130\nselect * from activity_searches where user_id = 7783;\nselect * from activity_search_filters where activity_search_id IN (32291, 32292);\n\nSELECT asf.activity_search_id, asf.id, asf.value\nFROM activity_search_filters asf\nWHERE asf.filter = 'group_id'\nAND asf.value IN (\n SELECT CONCAT(\n HEX(SUBSTR(uuid, 5, 4)), '-',\n HEX(SUBSTR(uuid, 3, 2)), '-',\n HEX(SUBSTR(uuid, 1, 2)), '-',\n HEX(SUBSTR(uuid, 9, 2)), '-',\n HEX(SUBSTR(uuid, 11))\n )\n FROM groups\n WHERE deleted_at IS NOT NULL\n);\n\nSELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th\n# ********************************************************************\nSELECT * FROM crm_configurations where provider = 'hubspot';\nSELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133\nSELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null\n# ********************************************************************\n\nselect * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';\nselect\n cp.*\n# DISTINCT t.id\n# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields\nFROM crm_profiles cp\nJOIN crm_configurations crm on crm.id = cp.crm_configuration_id\nJOIN users u on u.id = cp.user_id\nJOIN teams t ON t.id = crm.team_id\nWHERE crm.provider = 'salesforce' and t.status = 'active'\n and cp.archived_at IS NULL and u.deleted_at IS NULL\n and t.id NOT IN (1093)\n and t.id = 2\n and cp.contact_fields IS NULL;\n# and c.crm_provider_id = '003Uu00000ojD4NIAU';\n\nSELECT * FROM users WHERE id = 26484;\nSELECT * FROM crm_profiles WHERE user_id = 26484;\nSELECT * FROM social_accounts WHERE sociable_id = 26484;\nSELECT * FROM crm_configurations where provider = 'salesforce';\nselect * from users where id IN (10022, 10403);\nselect * from users where team_id IN (526);\nselect * from teams where id IN (526, 532);\nselect * from crm_configurations where id IN (500, 516);\nselect * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);\nselect * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 526 and sa.provider = 'salesforce';\nselect * from team_settings where team_id IN (526, 532);\n\nselect * from users where id IN (22824);\nselect * from crm_profiles where crm_configuration_id IN (1026);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1093 and sa.provider = 'salesforce';\n\nselect * from teams where id = 1099;\nselect * from users where id = 29643\n\nselect * from activity_processing_states;\n\nSELECT * FROM teams where name LIKE '%Fare%'; # 233\nSELECT * FROM opportunities where crm_configuration_id = 215\n# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'\n;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1088 and sa.provider = 'hubspot';\n\nSELECT * FROM teams order by updated_at DESC\nSELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account\n\nselect * from crm_configurations where provider = 'pipedrive';\n\nselect * from teams where id = 957;\nselect * from crm_configurations where id = 957;\n\nSELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743\nSELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;\n\nselect * from users where team_id = 1; # 26726 - Gabriela Dureva\nSELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific\nselect * from activities where user_id = 26726 order by id desc;\nselect * from contacts where crm_configuration_id = 1\nand email IN ('charlotte.ward@prolific.com', 'frankie.bryant@prolific.com'); # 2094416, 2093620\nSELECT * FROM contacts WHERE id = 6284931;\n\nSELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id\nWHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;\n\nselect * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);\nselect * from crm_configurations where id = 1;\n\n43801692-1aeb-32ce-acba-5b80a479701a\n44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b\n405975c0-b3d0-7aaa-821f-09d59cae6dd1\n4caf848d-4bed-2299-b248-7788d41f9fca\n49bedc3f-f196-eef3-89c3-dea6a3b4aa63\n43420989-a09d-b8f8-9806-c8bbf7a02aac\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nSELECT * FROM activities WHERE id = 75461988;\n\nSELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;\n\nselect * from contacts where id = 17900517;\n\nselect * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id\nwhere crm.provider != 'salesforce';\n\nselect * from users where id = 21047;\nSELECT * FROM crm_configurations WHERE id = 892;\nSELECT * FROM teams WHERE id = 942;\nselect * from opportunities where team_id = 942 order by updated_at desc;\nselect * from contacts where team_id = 942 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 942 and sa.provider = 'hubspot';\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430\nSELECT * FROM crm_configurations WHERE id = 1;\nSELECT * FROM teams WHERE crm_id = 1;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nselect id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1\nSELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430\n\nselect * from teams where id = 852;\nselect * from groups where id = 2286;\nselect * from sidekick_settings where team_id = 852;\nselect * from default_activity_types where team_id = 852;\n\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1 AND u.deleted_at IS NULL\nAND u.crm_required = 1\nAND u.team_id = 1\nORDER BY u.team_id;\n\nSELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (\n18481\n );\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1\n AND u.deleted_at IS NULL\n AND u.crm_required = 1\n# AND u.team_id = 1\n AND p.id IS NULL -- Move this condition to WHERE clause\nORDER BY u.team_id;\n\nSELECT * FROM opportunities WHERE id = 20002609;\nselect * from teams where id = 1122; # Velatir, 29953 - christian@velatir.com\nselect * from crm_configurations where id = 1060;\nselect * from crm_layouts where crm_configuration_id = 1060;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1122 and sa.provider = 'hubspot';\nselect * from opportunities where team_id = 1122 order by updated_at desc;\n\nselect * from crm_field_data where object_type = 'contact';\n\nSELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 248 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS\nSELECT * FROM users where id = 24115;\nSELECT * FROM accounts where id = 4002896;\nSELECT * FROM teams WHERE name LIKE '%adswerve%';\nSELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN (\"0069N000003GIQ9QAO\",\"0061r000019yGP9AAM\",\"0066900001S2KWlAAN\",\"0066900001TDpj2AAD\",\"0066900001b8uEwAAI\",\"0069N000001rQi0QAE\",\"006QF00000KD40mYAD\",\"006QF00000LzpRJYAZ\",\"0069N000002uomtQAA\",\"0069N000002xlMLQAY\",\"0066900001NV6ubAAD\",\"0061r00001HJp45AAD\",\"006QF00000uTlUoYAK\",\"006QF00000v0bZqYAI\");\nSELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203\n\nSELECT u.id, u.email, ac.name, a.* FROM activities a\nJOIN users u ON a.user_id = u.id\nJOIN accounts ac ON a.account_id = ac.id\nWHERE\nuuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or\nuuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or\nuuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;\n\nselect * from users where id = 5825;\nSELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;\n\nselect * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;\n19594, 862\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 862 and sa.provider = 'salesforce';\n\nselect * from automated_reports where id = 36;\nselect ar.frequency, r.*, ar.* from automated_report_results r\njoin automated_reports ar on r.report_id = ar.id\nwhere ar.frequency != 'one_off';\n\nselect s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;\nselect * from nudges n where n.activity_search_id\n\nselect * from teams where created_at > '2026-03-09';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;\n\nselect * from users where team_id = 1 and name like '%Lukas%'; # 7160\n\nSELECT * FROM teams WHERE id = 575;\nselect * from opportunities where team_id = 575;\nSELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,\nselect * from opportunities where team_id = 1126;\nSELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,\nselect * from opportunities where team_id = 1125;\nselect * from contacts c\nwhere c.team_id = 882;\n\nSELECT * FROM activities WHERE id = 76822967;\nSELECT * FROM crm_profiles WHERE user_id = 15440;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 555;\nSELECT * FROM crm_configurations WHERE id = 555;\nSELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 581 and sa.provider = 'salesforce';\n\nSELECT * FROM automated_report_results order by id desc;\n\nselect * from features;\nselect * from team_features where feature_id = 40;\n\nselect * from teams where id = 556;\n\nselect * from automated_reports;\nwhere id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , [\"pdf\",\"podcast\"]\nSELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;\nselect * from automated_report_results order by id desc;\nSELECT * FROM automated_report_results WHERE id = 1919;\n\nselect * from automated_report_results WHERE report_id = 54;\n\nselect * from opportunities where id = 7594349;\n\nSELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - jiminnyintegration@lesmills.com\nselect * from playbooks where team_id = 711; # event 226147\nSELECT * FROM playbook_categories WHERE playbook_id = 5515;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';\nSELECT * FROM crm_fields WHERE id = 226147;\nSELECT * FROM crm_field_values WHERE crm_field_id = 226147;\n\nSELECT * FROM crm_configurations WHERE id = 692;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 711 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;\n\nselect * from leads;\n\nselect * from calendars;\n\nSELECT\n t.id AS team_id,\n t.name,\n LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain\nFROM teams t\nJOIN users u ON u.team_id = t.id\nJOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'\nLEFT JOIN team_domains td\n ON td.team_id = t.id\n AND td.deleted_at IS NULL\n AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))\nGROUP BY t.id, t.name, calendar_domain\nORDER BY t.name, calendar_domain;\n\nselect * from users u join calendars c on c.user_id = u.id\nwhere u.team_id = 882;\n\n\nselect * from activities where id = 74049485; # team 563 crm 537\nselect * from activities where id = 73272382; # team 563 crm 537\nselect * from activities where id = 64400389; # team 563 crm 537\nselect * from activities where id = 58081273; # team 563 crm 537\nselect * from activities where id = 54520297; # team 563 crm 537\nselect * from participants where activity_id = 58081273;\n\nselect * from activities where crm_configuration_id = 537 and provider = 'aircall'\nand account_id = 19003658 order by updated_at desc;\n\nselect * from contacts where crm_configuration_id = 537 and id = 35957759;\nselect * from accounts where crm_configuration_id = 537 and id = 19003658;\n\nselect * from automated_report_results where id = 1976;\nselect * from automated_reports where id = 583;\nselect * from activity_searches where id = 87714;\nselect * from activity_search_filters where activity_search_id = 87714;\n\nSELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid\nor uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;\n\nSELECT * FROM crm_configurations WHERE provider = 'hubspot';\nselect * from rate_limits;\n\nselect * from automated_report_results where media_type = 'pdf' and status = 2\nand id IN (18, 1872);\nselect * from automated_reports where id = 54;\nSELECT * FROM users WHERE id IN (24623,29443,29613);\n\nSELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
6985417326322133673
|
2218600145176901197
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
40
1
40
64
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993
SELECT * FROM users WHERE id = 25061;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 994;
SELECT * FROM crm_profiles WHERE user_id = 25061;
select * from crm_configurations where id = 834;
SELECT * FROM teams WHERE id = 882;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;
SELECT * FROM contacts where crm_configuration_id = 834;
SELECT * FROM opportunities WHERE team_id = 933
# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');
AND id IN (8482561,18352941,19042734,19232139,19445140,19472541);
SELECT * FROM opportunity_contacts
WHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 485; #
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
select crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id
where crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')
# and l.converted_at IS NOT NULL
;
# [PASSWORD_DOTS]
SELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')
and opportunity_id IS NULL
order by id desc;
SELECT * FROM teams WHERE id = 604; # 598
SELECT * FROM activities WHERE id = 74410828; # [EMAIL]
SELECT * FROM accounts WHERE id = 20068382;
SELECT * FROM accounts WHERE id = 35186038;
SELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 559 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;
select * from sidekick_settings where team_id = 781;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100
SELECT * FROM crm_layouts WHERE crm_configuration_id = 711;
SELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL
and is_internal = 0 and status = 'completed'
order by id desc;
SELECT * FROM crm_layout_entities
WHERE crm_layout_id IN (2352, 2353);
;
SELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 556 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;
SELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;
select * from contacts
where crm_configuration_id = 530
and crm_provider_id = 872252;
select * from activities where crm_configuration_id = 530
and user_id = 14343 and type like '%softphone%'
and created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);
SELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t
JOIN crm_configurations c ON t.id = c.team_id
WHERE t.status = 'active';
SELECT * FROM teams where id = 1091;
SELECT * FROM crm_configurations where team_id = 1091;
SELECT * FROM activity_providers where team_id = 1091;
SELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT * FROM teams WHERE name LIKE '%Leadventure%';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1091 and sa.provider = 'salesforce';
SELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812
SELECT * FROM teams where id = 862;
SELECT * FROM crm_configurations where team_id = 862;
SELECT * FROM activity_providers where team_id = 862;
SELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT t.id, crm.id, crm.provider, ap.* FROM teams t
join crm_configurations crm on t.id = crm.team_id
join activity_providers ap on t.id = ap.team_id
where t.status = 'active' and ap.is_enabled = 1
and crm.provider = 'hubspot'
and ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',
'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');
SELECT * FROM teams where id = 1068;
SELECT * FROM crm_configurations where team_id = 1068;
SELECT * FROM activity_providers where team_id = 1068;
SELECT * FROM activities a
where crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')
and a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'
)
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by a.id desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1068 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262
SELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
select * from crm_layouts where crm_configuration_id = 834;
select * from crm_layout_entities where crm_layout_id = 2780;
select * from crm_fields where id IN (321153,321192,321193,321194);
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1057 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8
SELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20
SELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10
SELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #
SELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;
select * from users where team_id = 51; # 7783
SELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130
select * from activity_searches where user_id = 7783;
select * from activity_search_filters where activity_search_id IN (32291, 32292);
SELECT asf.activity_search_id, asf.id, asf.value
FROM activity_search_filters asf
WHERE asf.filter = 'group_id'
AND asf.value IN (
SELECT CONCAT(
HEX(SUBSTR(uuid, 5, 4)), '-',
HEX(SUBSTR(uuid, 3, 2)), '-',
HEX(SUBSTR(uuid, 1, 2)), '-',
HEX(SUBSTR(uuid, 9, 2)), '-',
HEX(SUBSTR(uuid, 11))
)
FROM groups
WHERE deleted_at IS NOT NULL
);
SELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where provider = 'hubspot';
SELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133
SELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null
# [PASSWORD_DOTS]
select * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';
select
cp.*
# DISTINCT t.id
# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields
FROM crm_profiles cp
JOIN crm_configurations crm on crm.id = cp.crm_configuration_id
JOIN users u on u.id = cp.user_id
JOIN teams t ON t.id = crm.team_id
WHERE crm.provider = 'salesforce' and t.status = 'active'
and cp.archived_at IS NULL and u.deleted_at IS NULL
and t.id NOT IN (1093)
and t.id = 2
and cp.contact_fields IS NULL;
# and c.crm_provider_id = '003Uu00000ojD4NIAU';
SELECT * FROM users WHERE id = 26484;
SELECT * FROM crm_profiles WHERE user_id = 26484;
SELECT * FROM social_accounts WHERE sociable_id = 26484;
SELECT * FROM crm_configurations where provider = 'salesforce';
select * from users where id IN (10022, 10403);
select * from users where team_id IN (526);
select * from teams where id IN (526, 532);
select * from crm_configurations where id IN (500, 516);
select * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);
select * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 526 and sa.provider = 'salesforce';
select * from team_settings where team_id IN (526, 532);
select * from users where id IN (22824);
select * from crm_profiles where crm_configuration_id IN (1026);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1093 and sa.provider = 'salesforce';
select * from teams where id = 1099;
select * from users where id = 29643
select * from activity_processing_states;
SELECT * FROM teams where name LIKE '%Fare%'; # 233
SELECT * FROM opportunities where crm_configuration_id = 215
# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'
;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1088 and sa.provider = 'hubspot';
SELECT * FROM teams order by updated_at DESC
SELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account
select * from crm_configurations where provider = 'pipedrive';
select * from teams where id = 957;
select * from crm_configurations where id = 957;
SELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743
SELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;
select * from users where team_id = 1; # 26726 - Gabriela Dureva
SELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific
select * from activities where user_id = 26726 order by id desc;
select * from contacts where crm_configuration_id = 1
and email IN ('[EMAIL]', '[EMAIL]'); # 2094416, 2093620
SELECT * FROM contacts WHERE id = 6284931;
SELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id
WHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;
select * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);
select * from crm_configurations where id = 1;
43801692-1aeb-32ce-acba-5b80a479701a
44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b
405975c0-b3d0-7aaa-821f-09d59cae6dd1
4caf848d-4bed-2299-b248-7788d41f9fca
49bedc3f-f196-eef3-89c3-dea6a3b4aa63
43420989-a09d-b8f8-9806-c8bbf7a02aac
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
SELECT * FROM activities WHERE id = 75461988;
SELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;
select * from contacts where id = 17900517;
select * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id
where crm.provider != 'salesforce';
select * from users where id = 21047;
SELECT * FROM crm_configurations WHERE id = 892;
SELECT * FROM teams WHERE id = 942;
select * from opportunities where team_id = 942 order by updated_at desc;
select * from contacts where team_id = 942 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 942 and sa.provider = 'hubspot';
SELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430
SELECT * FROM crm_configurations WHERE id = 1;
SELECT * FROM teams WHERE crm_id = 1;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
select id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1
SELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430
select * from teams where id = 852;
select * from groups where id = 2286;
select * from sidekick_settings where team_id = 852;
select * from default_activity_types where team_id = 852;
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1 AND u.deleted_at IS NULL
AND u.crm_required = 1
AND u.team_id = 1
ORDER BY u.team_id;
SELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (
18481
);
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1
AND u.deleted_at IS NULL
AND u.crm_required = 1
# AND u.team_id = 1
AND p.id IS NULL -- Move this condition to WHERE clause
ORDER BY u.team_id;
SELECT * FROM opportunities WHERE id = 20002609;
select * from teams where id = 1122; # Velatir, 29953 - [EMAIL]
select * from crm_configurations where id = 1060;
select * from crm_layouts where crm_configuration_id = 1060;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1122 and sa.provider = 'hubspot';
select * from opportunities where team_id = 1122 order by updated_at desc;
select * from crm_field_data where object_type = 'contact';
SELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 248 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS
SELECT * FROM users where id = 24115;
SELECT * FROM accounts where id = 4002896;
SELECT * FROM teams WHERE name LIKE '%adswerve%';
SELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN ("0069N000003GIQ9QAO","0061r000019yGP9AAM","0066900001S2KWlAAN","0066900001TDpj2AAD","0066900001b8uEwAAI","0069N000001rQi0QAE","006QF00000KD40mYAD","006QF00000LzpRJYAZ","0069N000002uomtQAA","0069N000002xlMLQAY","0066900001NV6ubAAD","0061r00001HJp45AAD","006QF00000uTlUoYAK","006QF00000v0bZqYAI");
SELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203
SELECT u.id, u.email, ac.name, a.* FROM activities a
JOIN users u ON a.user_id = u.id
JOIN accounts ac ON a.account_id = ac.id
WHERE
uuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or
uuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or
uuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;
select * from users where id = 5825;
SELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;
select * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;
19594, 862
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 862 and sa.provider = 'salesforce';
select * from automated_reports where id = 36;
select ar.frequency, r.*, ar.* from automated_report_results r
join automated_reports ar on r.report_id = ar.id
where ar.frequency != 'one_off';
select s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;
select * from nudges n where n.activity_search_id
select * from teams where created_at > '2026-03-09';
SELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;
select * from users where team_id = 1 and name like '%Lukas%'; # 7160
SELECT * FROM teams WHERE id = 575;
select * from opportunities where team_id = 575;
SELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,
select * from opportunities where team_id = 1126;
SELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,
select * from opportunities where team_id = 1125;
select * from contacts c
where c.team_id = 882;
SELECT * FROM activities WHERE id = 76822967;
SELECT * FROM crm_profiles WHERE user_id = 15440;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 555;
SELECT * FROM crm_configurations WHERE id = 555;
SELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 581 and sa.provider = 'salesforce';
SELECT * FROM automated_report_results order by id desc;
select * from features;
select * from team_features where feature_id = 40;
select * from teams where id = 556;
select * from automated_reports;
where id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , ["pdf","podcast"]
SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;
select * from automated_report_results order by id desc;
SELECT * FROM automated_report_results WHERE id = 1919;
select * from automated_report_results WHERE report_id = 54;
select * from opportunities where id = 7594349;
SELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - [EMAIL]
select * from playbooks where team_id = 711; # event 226147
SELECT * FROM playbook_categories WHERE playbook_id = 5515;
SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';
SELECT * FROM crm_fields WHERE id = 226147;
SELECT * FROM crm_field_values WHERE crm_field_id = 226147;
SELECT * FROM crm_configurations WHERE id = 692;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 711 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;
select * from leads;
select * from calendars;
SELECT
t.id AS team_id,
t.name,
LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain
FROM teams t
JOIN users u ON u.team_id = t.id
JOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'
LEFT JOIN team_domains td
ON td.team_id = t.id
AND td.deleted_at IS NULL
AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))
GROUP BY t.id, t.name, calendar_domain
ORDER BY t.name, calendar_domain;
select * from users u join calendars c on c.user_id = u.id
where u.team_id = 882;
select * from activities where id = 74049485; # team 563 crm 537
select * from activities where id = 73272382; # team 563 crm 537
select * from activities where id = 64400389; # team 563 crm 537
select * from activities where id = 58081273; # team 563 crm 537
select * from activities where id = 54520297; # team 563 crm 537
select * from participants where activity_id = 58081273;
select * from activities where crm_configuration_id = 537 and provider = 'aircall'
and account_id = 19003658 order by updated_at desc;
select * from contacts where crm_configuration_id = 537 and id = 35957759;
select * from accounts where crm_configuration_id = 537 and id = 19003658;
select * from automated_report_results where id = 1976;
select * from automated_reports where id = 583;
select * from activity_searches where id = 87714;
select * from activity_search_filters where activity_search_id = 87714;
SELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid
or uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;
SELECT * FROM crm_configurations WHERE provider = 'hubspot';
select * from rate_limits;
select * from automated_report_results where media_type = 'pdf' and status = 2
and id IN (18, 1872);
select * from automated_reports where id = 54;
SELECT * FROM users WHERE id IN (24623,29443,29613);
SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
33558
|
NULL
|
NULL
|
NULL
|
|
33561
|
1275
|
23
|
2026-05-13T10:33:32.421437+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668412421_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
40
1
40
64
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993
SELECT * FROM users WHERE id = 25061;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 994;
SELECT * FROM crm_profiles WHERE user_id = 25061;
select * from crm_configurations where id = 834;
SELECT * FROM teams WHERE id = 882;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;
SELECT * FROM contacts where crm_configuration_id = 834;
SELECT * FROM opportunities WHERE team_id = 933
# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');
AND id IN (8482561,18352941,19042734,19232139,19445140,19472541);
SELECT * FROM opportunity_contacts
WHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 485; #
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
select crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id
where crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')
# and l.converted_at IS NOT NULL
;
# [PASSWORD_DOTS]
SELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')
and opportunity_id IS NULL
order by id desc;
SELECT * FROM teams WHERE id = 604; # 598
SELECT * FROM activities WHERE id = 74410828; # [EMAIL]
SELECT * FROM accounts WHERE id = 20068382;
SELECT * FROM accounts WHERE id = 35186038;
SELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 559 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;
select * from sidekick_settings where team_id = 781;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100
SELECT * FROM crm_layouts WHERE crm_configuration_id = 711;
SELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL
and is_internal = 0 and status = 'completed'
order by id desc;
SELECT * FROM crm_layout_entities
WHERE crm_layout_id IN (2352, 2353);
;
SELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 556 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;
SELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;
select * from contacts
where crm_configuration_id = 530
and crm_provider_id = 872252;
select * from activities where crm_configuration_id = 530
and user_id = 14343 and type like '%softphone%'
and created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);
SELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t
JOIN crm_configurations c ON t.id = c.team_id
WHERE t.status = 'active';
SELECT * FROM teams where id = 1091;
SELECT * FROM crm_configurations where team_id = 1091;
SELECT * FROM activity_providers where team_id = 1091;
SELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT * FROM teams WHERE name LIKE '%Leadventure%';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1091 and sa.provider = 'salesforce';
SELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812
SELECT * FROM teams where id = 862;
SELECT * FROM crm_configurations where team_id = 862;
SELECT * FROM activity_providers where team_id = 862;
SELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT t.id, crm.id, crm.provider, ap.* FROM teams t
join crm_configurations crm on t.id = crm.team_id
join activity_providers ap on t.id = ap.team_id
where t.status = 'active' and ap.is_enabled = 1
and crm.provider = 'hubspot'
and ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',
'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');
SELECT * FROM teams where id = 1068;
SELECT * FROM crm_configurations where team_id = 1068;
SELECT * FROM activity_providers where team_id = 1068;
SELECT * FROM activities a
where crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')
and a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'
)
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by a.id desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1068 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262
SELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
select * from crm_layouts where crm_configuration_id = 834;
select * from crm_layout_entities where crm_layout_id = 2780;
select * from crm_fields where id IN (321153,321192,321193,321194);
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1057 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8
SELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20
SELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10
SELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #
SELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;
select * from users where team_id = 51; # 7783
SELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130
select * from activity_searches where user_id = 7783;
select * from activity_search_filters where activity_search_id IN (32291, 32292);
SELECT asf.activity_search_id, asf.id, asf.value
FROM activity_search_filters asf
WHERE asf.filter = 'group_id'
AND asf.value IN (
SELECT CONCAT(
HEX(SUBSTR(uuid, 5, 4)), '-',
HEX(SUBSTR(uuid, 3, 2)), '-',
HEX(SUBSTR(uuid, 1, 2)), '-',
HEX(SUBSTR(uuid, 9, 2)), '-',
HEX(SUBSTR(uuid, 11))
)
FROM groups
WHERE deleted_at IS NOT NULL
);
SELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where provider = 'hubspot';
SELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133
SELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null
# [PASSWORD_DOTS]
select * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';
select
cp.*
# DISTINCT t.id
# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields
FROM crm_profiles cp
JOIN crm_configurations crm on crm.id = cp.crm_configuration_id
JOIN users u on u.id = cp.user_id
JOIN teams t ON t.id = crm.team_id
WHERE crm.provider = 'salesforce' and t.status = 'active'
and cp.archived_at IS NULL and u.deleted_at IS NULL
and t.id NOT IN (1093)
and t.id = 2
and cp.contact_fields IS NULL;
# and c.crm_provider_id = '003Uu00000ojD4NIAU';
SELECT * FROM users WHERE id = 26484;
SELECT * FROM crm_profiles WHERE user_id = 26484;
SELECT * FROM social_accounts WHERE sociable_id = 26484;
SELECT * FROM crm_configurations where provider = 'salesforce';
select * from users where id IN (10022, 10403);
select * from users where team_id IN (526);
select * from teams where id IN (526, 532);
select * from crm_configurations where id IN (500, 516);
select * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);
select * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 526 and sa.provider = 'salesforce';
select * from team_settings where team_id IN (526, 532);
select * from users where id IN (22824);
select * from crm_profiles where crm_configuration_id IN (1026);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1093 and sa.provider = 'salesforce';
select * from teams where id = 1099;
select * from users where id = 29643
select * from activity_processing_states;
SELECT * FROM teams where name LIKE '%Fare%'; # 233
SELECT * FROM opportunities where crm_configuration_id = 215
# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'
;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1088 and sa.provider = 'hubspot';
SELECT * FROM teams order by updated_at DESC
SELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account
select * from crm_configurations where provider = 'pipedrive';
select * from teams where id = 957;
select * from crm_configurations where id = 957;
SELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743
SELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;
select * from users where team_id = 1; # 26726 - Gabriela Dureva
SELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific
select * from activities where user_id = 26726 order by id desc;
select * from contacts where crm_configuration_id = 1
and email IN ('[EMAIL]', '[EMAIL]'); # 2094416, 2093620
SELECT * FROM contacts WHERE id = 6284931;
SELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id
WHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;
select * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);
select * from crm_configurations where id = 1;
43801692-1aeb-32ce-acba-5b80a479701a
44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b
405975c0-b3d0-7aaa-821f-09d59cae6dd1
4caf848d-4bed-2299-b248-7788d41f9fca
49bedc3f-f196-eef3-89c3-dea6a3b4aa63
43420989-a09d-b8f8-9806-c8bbf7a02aac
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
SELECT * FROM activities WHERE id = 75461988;
SELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;
select * from contacts where id = 17900517;
select * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id
where crm.provider != 'salesforce';
select * from users where id = 21047;
SELECT * FROM crm_configurations WHERE id = 892;
SELECT * FROM teams WHERE id = 942;
select * from opportunities where team_id = 942 order by updated_at desc;
select * from contacts where team_id = 942 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 942 and sa.provider = 'hubspot';
SELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430
SELECT * FROM crm_configurations WHERE id = 1;
SELECT * FROM teams WHERE crm_id = 1;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
select id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1
SELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430
select * from teams where id = 852;
select * from groups where id = 2286;
select * from sidekick_settings where team_id = 852;
select * from default_activity_types where team_id = 852;
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1 AND u.deleted_at IS NULL
AND u.crm_required = 1
AND u.team_id = 1
ORDER BY u.team_id;
SELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (
18481
);
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1
AND u.deleted_at IS NULL
AND u.crm_required = 1
# AND u.team_id = 1
AND p.id IS NULL -- Move this condition to WHERE clause
ORDER BY u.team_id;
SELECT * FROM opportunities WHERE id = 20002609;
select * from teams where id = 1122; # Velatir, 29953 - [EMAIL]
select * from crm_configurations where id = 1060;
select * from crm_layouts where crm_configuration_id = 1060;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1122 and sa.provider = 'hubspot';
select * from opportunities where team_id = 1122 order by updated_at desc;
select * from crm_field_data where object_type = 'contact';
SELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 248 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS
SELECT * FROM users where id = 24115;
SELECT * FROM accounts where id = 4002896;
SELECT * FROM teams WHERE name LIKE '%adswerve%';
SELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN ("0069N000003GIQ9QAO","0061r000019yGP9AAM","0066900001S2KWlAAN","0066900001TDpj2AAD","0066900001b8uEwAAI","0069N000001rQi0QAE","006QF00000KD40mYAD","006QF00000LzpRJYAZ","0069N000002uomtQAA","0069N000002xlMLQAY","0066900001NV6ubAAD","0061r00001HJp45AAD","006QF00000uTlUoYAK","006QF00000v0bZqYAI");
SELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203
SELECT u.id, u.email, ac.name, a.* FROM activities a
JOIN users u ON a.user_id = u.id
JOIN accounts ac ON a.account_id = ac.id
WHERE
uuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or
uuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or
uuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;
select * from users where id = 5825;
SELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;
select * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;
19594, 862
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 862 and sa.provider = 'salesforce';
select * from automated_reports where id = 36;
select ar.frequency, r.*, ar.* from automated_report_results r
join automated_reports ar on r.report_id = ar.id
where ar.frequency != 'one_off';
select s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;
select * from nudges n where n.activity_search_id
select * from teams where created_at > '2026-03-09';
SELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;
select * from users where team_id = 1 and name like '%Lukas%'; # 7160
SELECT * FROM teams WHERE id = 575;
select * from opportunities where team_id = 575;
SELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,
select * from opportunities where team_id = 1126;
SELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,
select * from opportunities where team_id = 1125;
select * from contacts c
where c.team_id = 882;
SELECT * FROM activities WHERE id = 76822967;
SELECT * FROM crm_profiles WHERE user_id = 15440;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 555;
SELECT * FROM crm_configurations WHERE id = 555;
SELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 581 and sa.provider = 'salesforce';
SELECT * FROM automated_report_results order by id desc;
select * from features;
select * from team_features where feature_id = 40;
select * from teams where id = 556;
select * from automated_reports;
where id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , ["pdf","podcast"]
SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;
select * from automated_report_results order by id desc;
SELECT * FROM automated_report_results WHERE id = 1919;
select * from automated_report_results WHERE report_id = 54;
select * from opportunities where id = 7594349;
SELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - [EMAIL]
select * from playbooks where team_id = 711; # event 226147
SELECT * FROM playbook_categories WHERE playbook_id = 5515;
SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';
SELECT * FROM crm_fields WHERE id = 226147;
SELECT * FROM crm_field_values WHERE crm_field_id = 226147;
SELECT * FROM crm_configurations WHERE id = 692;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 711 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;
select * from leads;
select * from calendars;
SELECT
t.id AS team_id,
t.name,
LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain
FROM teams t
JOIN users u ON u.team_id = t.id
JOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'
LEFT JOIN team_domains td
ON td.team_id = t.id
AND td.deleted_at IS NULL
AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))
GROUP BY t.id, t.name, calendar_domain
ORDER BY t.name, calendar_domain;
select * from users u join calendars c on c.user_id = u.id
where u.team_id = 882;
select * from activities where id = 74049485; # team 563 crm 537
select * from activities where id = 73272382; # team 563 crm 537
select * from activities where id = 64400389; # team 563 crm 537
select * from activities where id = 58081273; # team 563 crm 537
select * from activities where id = 54520297; # team 563 crm 537
select * from participants where activity_id = 58081273;
select * from activities where crm_configuration_id = 537 and provider = 'aircall'
and account_id = 19003658 order by updated_at desc;
select * from contacts where crm_configuration_id = 537 and id = 35957759;
select * from accounts where crm_configuration_id = 537 and id = 19003658;
select * from automated_report_results where id = 1976;
select * from automated_reports where id = 583;
select * from activity_searches where id = 87714;
select * from activity_search_filters where activity_search_id = 87714;
SELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid
or uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;
SELECT * FROM crm_configurations WHERE provider = 'hubspot';
select * from rate_limits;
select * from automated_report_results where media_type = 'pdf' and status = 2
and id IN (18, 1872);
select * from automated_reports where id = 54;
SELECT * FROM users WHERE id IN (24623,29443,29613);
SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzing…","depth":4,"bounds":{"left":0.3849734,"top":0.10055866,"width":0.019946808,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","depth":4,"bounds":{"left":0.122340426,"top":0.07661612,"width":0.2855718,"height":0.9233839},"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.40957448,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"bounds":{"left":0.41821808,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"bounds":{"left":0.42918882,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"bounds":{"left":0.43783244,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"bounds":{"left":0.44647607,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"bounds":{"left":0.4574468,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.46841756,"top":0.09896249,"width":0.024268618,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.4950133,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.50598407,"top":0.09896249,"width":0.029587766,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.7084442,"top":0.09896249,"width":0.02825798,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"40","depth":4,"bounds":{"left":0.67785907,"top":0.123703115,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.69015956,"top":0.123703115,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"40","depth":4,"bounds":{"left":0.6994681,"top":0.123703115,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"64","depth":4,"bounds":{"left":0.7117686,"top":0.123703115,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7237367,"top":0.12210695,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.73105055,"top":0.12210695,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993\nSELECT * FROM users WHERE id = 25061;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 994;\nSELECT * FROM crm_profiles WHERE user_id = 25061;\n\nselect * from crm_configurations where id = 834;\nSELECT * FROM teams WHERE id = 882;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;\n\nSELECT * FROM contacts where crm_configuration_id = 834;\nSELECT * FROM opportunities WHERE team_id = 933\n# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');\nAND id IN (8482561,18352941,19042734,19232139,19445140,19472541);\nSELECT * FROM opportunity_contacts\nWHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 485; #\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nselect crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id\nwhere crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')\n# and l.converted_at IS NOT NULL\n;\n\n# ********************************************************************\nSELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')\nand opportunity_id IS NULL\norder by id desc;\n\nSELECT * FROM teams WHERE id = 604; # 598\nSELECT * FROM activities WHERE id = 74410828; # chelseaw@allvoices.co\nSELECT * FROM accounts WHERE id = 20068382;\nSELECT * FROM accounts WHERE id = 35186038;\n\nSELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 559 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;\nselect * from sidekick_settings where team_id = 781;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100\n\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 711;\nSELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL\nand is_internal = 0 and status = 'completed'\norder by id desc;\n\nSELECT * FROM crm_layout_entities\nWHERE crm_layout_id IN (2352, 2353);\n;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 556 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;\nSELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;\nselect * from contacts\nwhere crm_configuration_id = 530\nand crm_provider_id = 872252;\n\nselect * from activities where crm_configuration_id = 530\nand user_id = 14343 and type like '%softphone%'\nand created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);\n\n\nSELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t\nJOIN crm_configurations c ON t.id = c.team_id\nWHERE t.status = 'active';\n\nSELECT * FROM teams where id = 1091;\nSELECT * FROM crm_configurations where team_id = 1091;\nSELECT * FROM activity_providers where team_id = 1091;\nSELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT * FROM teams WHERE name LIKE '%Leadventure%';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1091 and sa.provider = 'salesforce';\n\nSELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812\nSELECT * FROM teams where id = 862;\nSELECT * FROM crm_configurations where team_id = 862;\nSELECT * FROM activity_providers where team_id = 862;\nSELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT t.id, crm.id, crm.provider, ap.* FROM teams t\njoin crm_configurations crm on t.id = crm.team_id\njoin activity_providers ap on t.id = ap.team_id\nwhere t.status = 'active' and ap.is_enabled = 1\nand crm.provider = 'hubspot'\nand ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',\n 'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');\n\nSELECT * FROM teams where id = 1068;\nSELECT * FROM crm_configurations where team_id = 1068;\nSELECT * FROM activity_providers where team_id = 1068;\n\nSELECT * FROM activities a\nwhere crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')\nand a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'\n )\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by a.id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1068 and sa.provider = 'hubspot';\n\n# ********************************************************************\n# ********************************************************************\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262\nSELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\nselect * from crm_layouts where crm_configuration_id = 834;\nselect * from crm_layout_entities where crm_layout_id = 2780;\nselect * from crm_fields where id IN (321153,321192,321193,321194);\n\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1057 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8\n\nSELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20\n\nSELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10\n\nSELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #\n\nSELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;\nselect * from users where team_id = 51; # 7783\nSELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130\nselect * from activity_searches where user_id = 7783;\nselect * from activity_search_filters where activity_search_id IN (32291, 32292);\n\nSELECT asf.activity_search_id, asf.id, asf.value\nFROM activity_search_filters asf\nWHERE asf.filter = 'group_id'\nAND asf.value IN (\n SELECT CONCAT(\n HEX(SUBSTR(uuid, 5, 4)), '-',\n HEX(SUBSTR(uuid, 3, 2)), '-',\n HEX(SUBSTR(uuid, 1, 2)), '-',\n HEX(SUBSTR(uuid, 9, 2)), '-',\n HEX(SUBSTR(uuid, 11))\n )\n FROM groups\n WHERE deleted_at IS NOT NULL\n);\n\nSELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th\n# ********************************************************************\nSELECT * FROM crm_configurations where provider = 'hubspot';\nSELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133\nSELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null\n# ********************************************************************\n\nselect * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';\nselect\n cp.*\n# DISTINCT t.id\n# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields\nFROM crm_profiles cp\nJOIN crm_configurations crm on crm.id = cp.crm_configuration_id\nJOIN users u on u.id = cp.user_id\nJOIN teams t ON t.id = crm.team_id\nWHERE crm.provider = 'salesforce' and t.status = 'active'\n and cp.archived_at IS NULL and u.deleted_at IS NULL\n and t.id NOT IN (1093)\n and t.id = 2\n and cp.contact_fields IS NULL;\n# and c.crm_provider_id = '003Uu00000ojD4NIAU';\n\nSELECT * FROM users WHERE id = 26484;\nSELECT * FROM crm_profiles WHERE user_id = 26484;\nSELECT * FROM social_accounts WHERE sociable_id = 26484;\nSELECT * FROM crm_configurations where provider = 'salesforce';\nselect * from users where id IN (10022, 10403);\nselect * from users where team_id IN (526);\nselect * from teams where id IN (526, 532);\nselect * from crm_configurations where id IN (500, 516);\nselect * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);\nselect * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 526 and sa.provider = 'salesforce';\nselect * from team_settings where team_id IN (526, 532);\n\nselect * from users where id IN (22824);\nselect * from crm_profiles where crm_configuration_id IN (1026);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1093 and sa.provider = 'salesforce';\n\nselect * from teams where id = 1099;\nselect * from users where id = 29643\n\nselect * from activity_processing_states;\n\nSELECT * FROM teams where name LIKE '%Fare%'; # 233\nSELECT * FROM opportunities where crm_configuration_id = 215\n# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'\n;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1088 and sa.provider = 'hubspot';\n\nSELECT * FROM teams order by updated_at DESC\nSELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account\n\nselect * from crm_configurations where provider = 'pipedrive';\n\nselect * from teams where id = 957;\nselect * from crm_configurations where id = 957;\n\nSELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743\nSELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;\n\nselect * from users where team_id = 1; # 26726 - Gabriela Dureva\nSELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific\nselect * from activities where user_id = 26726 order by id desc;\nselect * from contacts where crm_configuration_id = 1\nand email IN ('charlotte.ward@prolific.com', 'frankie.bryant@prolific.com'); # 2094416, 2093620\nSELECT * FROM contacts WHERE id = 6284931;\n\nSELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id\nWHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;\n\nselect * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);\nselect * from crm_configurations where id = 1;\n\n43801692-1aeb-32ce-acba-5b80a479701a\n44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b\n405975c0-b3d0-7aaa-821f-09d59cae6dd1\n4caf848d-4bed-2299-b248-7788d41f9fca\n49bedc3f-f196-eef3-89c3-dea6a3b4aa63\n43420989-a09d-b8f8-9806-c8bbf7a02aac\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nSELECT * FROM activities WHERE id = 75461988;\n\nSELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;\n\nselect * from contacts where id = 17900517;\n\nselect * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id\nwhere crm.provider != 'salesforce';\n\nselect * from users where id = 21047;\nSELECT * FROM crm_configurations WHERE id = 892;\nSELECT * FROM teams WHERE id = 942;\nselect * from opportunities where team_id = 942 order by updated_at desc;\nselect * from contacts where team_id = 942 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 942 and sa.provider = 'hubspot';\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430\nSELECT * FROM crm_configurations WHERE id = 1;\nSELECT * FROM teams WHERE crm_id = 1;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nselect id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1\nSELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430\n\nselect * from teams where id = 852;\nselect * from groups where id = 2286;\nselect * from sidekick_settings where team_id = 852;\nselect * from default_activity_types where team_id = 852;\n\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1 AND u.deleted_at IS NULL\nAND u.crm_required = 1\nAND u.team_id = 1\nORDER BY u.team_id;\n\nSELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (\n18481\n );\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1\n AND u.deleted_at IS NULL\n AND u.crm_required = 1\n# AND u.team_id = 1\n AND p.id IS NULL -- Move this condition to WHERE clause\nORDER BY u.team_id;\n\nSELECT * FROM opportunities WHERE id = 20002609;\nselect * from teams where id = 1122; # Velatir, 29953 - christian@velatir.com\nselect * from crm_configurations where id = 1060;\nselect * from crm_layouts where crm_configuration_id = 1060;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1122 and sa.provider = 'hubspot';\nselect * from opportunities where team_id = 1122 order by updated_at desc;\n\nselect * from crm_field_data where object_type = 'contact';\n\nSELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 248 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS\nSELECT * FROM users where id = 24115;\nSELECT * FROM accounts where id = 4002896;\nSELECT * FROM teams WHERE name LIKE '%adswerve%';\nSELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN (\"0069N000003GIQ9QAO\",\"0061r000019yGP9AAM\",\"0066900001S2KWlAAN\",\"0066900001TDpj2AAD\",\"0066900001b8uEwAAI\",\"0069N000001rQi0QAE\",\"006QF00000KD40mYAD\",\"006QF00000LzpRJYAZ\",\"0069N000002uomtQAA\",\"0069N000002xlMLQAY\",\"0066900001NV6ubAAD\",\"0061r00001HJp45AAD\",\"006QF00000uTlUoYAK\",\"006QF00000v0bZqYAI\");\nSELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203\n\nSELECT u.id, u.email, ac.name, a.* FROM activities a\nJOIN users u ON a.user_id = u.id\nJOIN accounts ac ON a.account_id = ac.id\nWHERE\nuuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or\nuuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or\nuuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;\n\nselect * from users where id = 5825;\nSELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;\n\nselect * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;\n19594, 862\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 862 and sa.provider = 'salesforce';\n\nselect * from automated_reports where id = 36;\nselect ar.frequency, r.*, ar.* from automated_report_results r\njoin automated_reports ar on r.report_id = ar.id\nwhere ar.frequency != 'one_off';\n\nselect s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;\nselect * from nudges n where n.activity_search_id\n\nselect * from teams where created_at > '2026-03-09';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;\n\nselect * from users where team_id = 1 and name like '%Lukas%'; # 7160\n\nSELECT * FROM teams WHERE id = 575;\nselect * from opportunities where team_id = 575;\nSELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,\nselect * from opportunities where team_id = 1126;\nSELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,\nselect * from opportunities where team_id = 1125;\nselect * from contacts c\nwhere c.team_id = 882;\n\nSELECT * FROM activities WHERE id = 76822967;\nSELECT * FROM crm_profiles WHERE user_id = 15440;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 555;\nSELECT * FROM crm_configurations WHERE id = 555;\nSELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 581 and sa.provider = 'salesforce';\n\nSELECT * FROM automated_report_results order by id desc;\n\nselect * from features;\nselect * from team_features where feature_id = 40;\n\nselect * from teams where id = 556;\n\nselect * from automated_reports;\nwhere id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , [\"pdf\",\"podcast\"]\nSELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;\nselect * from automated_report_results order by id desc;\nSELECT * FROM automated_report_results WHERE id = 1919;\n\nselect * from automated_report_results WHERE report_id = 54;\n\nselect * from opportunities where id = 7594349;\n\nSELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - jiminnyintegration@lesmills.com\nselect * from playbooks where team_id = 711; # event 226147\nSELECT * FROM playbook_categories WHERE playbook_id = 5515;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';\nSELECT * FROM crm_fields WHERE id = 226147;\nSELECT * FROM crm_field_values WHERE crm_field_id = 226147;\n\nSELECT * FROM crm_configurations WHERE id = 692;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 711 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;\n\nselect * from leads;\n\nselect * from calendars;\n\nSELECT\n t.id AS team_id,\n t.name,\n LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain\nFROM teams t\nJOIN users u ON u.team_id = t.id\nJOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'\nLEFT JOIN team_domains td\n ON td.team_id = t.id\n AND td.deleted_at IS NULL\n AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))\nGROUP BY t.id, t.name, calendar_domain\nORDER BY t.name, calendar_domain;\n\nselect * from users u join calendars c on c.user_id = u.id\nwhere u.team_id = 882;\n\n\nselect * from activities where id = 74049485; # team 563 crm 537\nselect * from activities where id = 73272382; # team 563 crm 537\nselect * from activities where id = 64400389; # team 563 crm 537\nselect * from activities where id = 58081273; # team 563 crm 537\nselect * from activities where id = 54520297; # team 563 crm 537\nselect * from participants where activity_id = 58081273;\n\nselect * from activities where crm_configuration_id = 537 and provider = 'aircall'\nand account_id = 19003658 order by updated_at desc;\n\nselect * from contacts where crm_configuration_id = 537 and id = 35957759;\nselect * from accounts where crm_configuration_id = 537 and id = 19003658;\n\nselect * from automated_report_results where id = 1976;\nselect * from automated_reports where id = 583;\nselect * from activity_searches where id = 87714;\nselect * from activity_search_filters where activity_search_id = 87714;\n\nSELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid\nor uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;\n\nSELECT * FROM crm_configurations WHERE provider = 'hubspot';\nselect * from rate_limits;\n\nselect * from automated_report_results where media_type = 'pdf' and status = 2\nand id IN (18, 1872);\nselect * from automated_reports where id = 54;\nSELECT * FROM users WHERE id IN (24623,29443,29613);\n\nSELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;","depth":4,"on_screen":true,"value":"SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993\nSELECT * FROM users WHERE id = 25061;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 994;\nSELECT * FROM crm_profiles WHERE user_id = 25061;\n\nselect * from crm_configurations where id = 834;\nSELECT * FROM teams WHERE id = 882;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;\n\nSELECT * FROM contacts where crm_configuration_id = 834;\nSELECT * FROM opportunities WHERE team_id = 933\n# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');\nAND id IN (8482561,18352941,19042734,19232139,19445140,19472541);\nSELECT * FROM opportunity_contacts\nWHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 485; #\nSELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\nselect crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id\nwhere crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')\n# and l.converted_at IS NOT NULL\n;\n\n# ********************************************************************\nSELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')\nand opportunity_id IS NULL\norder by id desc;\n\nSELECT * FROM teams WHERE id = 604; # 598\nSELECT * FROM activities WHERE id = 74410828; # chelseaw@allvoices.co\nSELECT * FROM accounts WHERE id = 20068382;\nSELECT * FROM accounts WHERE id = 35186038;\n\nSELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 559 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;\nselect * from sidekick_settings where team_id = 781;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100\n\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 711;\nSELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL\nand is_internal = 0 and status = 'completed'\norder by id desc;\n\nSELECT * FROM crm_layout_entities\nWHERE crm_layout_id IN (2352, 2353);\n;\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 556 and sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;\nSELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;\nselect * from contacts\nwhere crm_configuration_id = 530\nand crm_provider_id = 872252;\n\nselect * from activities where crm_configuration_id = 530\nand user_id = 14343 and type like '%softphone%'\nand created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';\n\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya\nSELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);\n\n\nSELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t\nJOIN crm_configurations c ON t.id = c.team_id\nWHERE t.status = 'active';\n\nSELECT * FROM teams where id = 1091;\nSELECT * FROM crm_configurations where team_id = 1091;\nSELECT * FROM activity_providers where team_id = 1091;\nSELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT * FROM teams WHERE name LIKE '%Leadventure%';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1091 and sa.provider = 'salesforce';\n\nSELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812\nSELECT * FROM teams where id = 862;\nSELECT * FROM crm_configurations where team_id = 862;\nSELECT * FROM activity_providers where team_id = 862;\nSELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\n\n\nSELECT t.id, crm.id, crm.provider, ap.* FROM teams t\njoin crm_configurations crm on t.id = crm.team_id\njoin activity_providers ap on t.id = ap.team_id\nwhere t.status = 'active' and ap.is_enabled = 1\nand crm.provider = 'hubspot'\nand ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',\n 'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');\n\nSELECT * FROM teams where id = 1068;\nSELECT * FROM crm_configurations where team_id = 1068;\nSELECT * FROM activity_providers where team_id = 1068;\n\nSELECT * FROM activities a\nwhere crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')\nand a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'\n )\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by a.id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1068 and sa.provider = 'hubspot';\n\n# ********************************************************************\n# ********************************************************************\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 933 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262\nSELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 882 and sa.provider = 'hubspot';\nselect * from crm_layouts where crm_configuration_id = 834;\nselect * from crm_layout_entities where crm_layout_id = 2780;\nselect * from crm_fields where id IN (321153,321192,321193,321194);\n\nSELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1057 and sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8\n\nSELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20\n\nSELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last\n\nSELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10\n\nSELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #\n\nSELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;\nselect * from users where team_id = 51; # 7783\nSELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130\nselect * from activity_searches where user_id = 7783;\nselect * from activity_search_filters where activity_search_id IN (32291, 32292);\n\nSELECT asf.activity_search_id, asf.id, asf.value\nFROM activity_search_filters asf\nWHERE asf.filter = 'group_id'\nAND asf.value IN (\n SELECT CONCAT(\n HEX(SUBSTR(uuid, 5, 4)), '-',\n HEX(SUBSTR(uuid, 3, 2)), '-',\n HEX(SUBSTR(uuid, 1, 2)), '-',\n HEX(SUBSTR(uuid, 9, 2)), '-',\n HEX(SUBSTR(uuid, 11))\n )\n FROM groups\n WHERE deleted_at IS NOT NULL\n);\n\nSELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th\n# ********************************************************************\nSELECT * FROM crm_configurations where provider = 'hubspot';\nSELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133\nSELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null\n# ********************************************************************\n\nselect * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';\nselect\n cp.*\n# DISTINCT t.id\n# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields\nFROM crm_profiles cp\nJOIN crm_configurations crm on crm.id = cp.crm_configuration_id\nJOIN users u on u.id = cp.user_id\nJOIN teams t ON t.id = crm.team_id\nWHERE crm.provider = 'salesforce' and t.status = 'active'\n and cp.archived_at IS NULL and u.deleted_at IS NULL\n and t.id NOT IN (1093)\n and t.id = 2\n and cp.contact_fields IS NULL;\n# and c.crm_provider_id = '003Uu00000ojD4NIAU';\n\nSELECT * FROM users WHERE id = 26484;\nSELECT * FROM crm_profiles WHERE user_id = 26484;\nSELECT * FROM social_accounts WHERE sociable_id = 26484;\nSELECT * FROM crm_configurations where provider = 'salesforce';\nselect * from users where id IN (10022, 10403);\nselect * from users where team_id IN (526);\nselect * from teams where id IN (526, 532);\nselect * from crm_configurations where id IN (500, 516);\nselect * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);\nselect * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 526 and sa.provider = 'salesforce';\nselect * from team_settings where team_id IN (526, 532);\n\nselect * from users where id IN (22824);\nselect * from crm_profiles where crm_configuration_id IN (1026);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1093 and sa.provider = 'salesforce';\n\nselect * from teams where id = 1099;\nselect * from users where id = 29643\n\nselect * from activity_processing_states;\n\nSELECT * FROM teams where name LIKE '%Fare%'; # 233\nSELECT * FROM opportunities where crm_configuration_id = 215\n# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'\n;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1088 and sa.provider = 'hubspot';\n\nSELECT * FROM teams order by updated_at DESC\nSELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account\n\nselect * from crm_configurations where provider = 'pipedrive';\n\nselect * from teams where id = 957;\nselect * from crm_configurations where id = 957;\n\nSELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743\nSELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;\n\nselect * from users where team_id = 1; # 26726 - Gabriela Dureva\nSELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific\nselect * from activities where user_id = 26726 order by id desc;\nselect * from contacts where crm_configuration_id = 1\nand email IN ('charlotte.ward@prolific.com', 'frankie.bryant@prolific.com'); # 2094416, 2093620\nSELECT * FROM contacts WHERE id = 6284931;\n\nSELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id\nWHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;\n\nselect * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);\nselect * from crm_configurations where id = 1;\n\n43801692-1aeb-32ce-acba-5b80a479701a\n44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b\n405975c0-b3d0-7aaa-821f-09d59cae6dd1\n4caf848d-4bed-2299-b248-7788d41f9fca\n49bedc3f-f196-eef3-89c3-dea6a3b4aa63\n43420989-a09d-b8f8-9806-c8bbf7a02aac\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nSELECT * FROM activities WHERE id = 75461988;\n\nSELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;\n\nselect * from contacts where id = 17900517;\n\nselect * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id\nwhere crm.provider != 'salesforce';\n\nselect * from users where id = 21047;\nSELECT * FROM crm_configurations WHERE id = 892;\nSELECT * FROM teams WHERE id = 942;\nselect * from opportunities where team_id = 942 order by updated_at desc;\nselect * from contacts where team_id = 942 order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 942 and sa.provider = 'hubspot';\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430\nSELECT * FROM crm_configurations WHERE id = 1;\nSELECT * FROM teams WHERE crm_id = 1;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1 and sa.provider = 'salesforce';\n\nselect id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1\nSELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430\n\nselect * from teams where id = 852;\nselect * from groups where id = 2286;\nselect * from sidekick_settings where team_id = 852;\nselect * from default_activity_types where team_id = 852;\n\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1 AND u.deleted_at IS NULL\nAND u.crm_required = 1\nAND u.team_id = 1\nORDER BY u.team_id;\n\nSELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (\n18481\n );\n\nSELECT cc.provider, cc.id, p.id, u.*\nFROM users u\nLEFT JOIN crm_profiles p ON u.id = p.user_id\nINNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'\nINNER JOIN crm_configurations cc ON t.crm_id = cc.id\nWHERE u.status = 1\n AND u.deleted_at IS NULL\n AND u.crm_required = 1\n# AND u.team_id = 1\n AND p.id IS NULL -- Move this condition to WHERE clause\nORDER BY u.team_id;\n\nSELECT * FROM opportunities WHERE id = 20002609;\nselect * from teams where id = 1122; # Velatir, 29953 - christian@velatir.com\nselect * from crm_configurations where id = 1060;\nselect * from crm_layouts where crm_configuration_id = 1060;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1122 and sa.provider = 'hubspot';\nselect * from opportunities where team_id = 1122 order by updated_at desc;\n\nselect * from crm_field_data where object_type = 'contact';\n\nSELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 248 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS\nSELECT * FROM users where id = 24115;\nSELECT * FROM accounts where id = 4002896;\nSELECT * FROM teams WHERE name LIKE '%adswerve%';\nSELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN (\"0069N000003GIQ9QAO\",\"0061r000019yGP9AAM\",\"0066900001S2KWlAAN\",\"0066900001TDpj2AAD\",\"0066900001b8uEwAAI\",\"0069N000001rQi0QAE\",\"006QF00000KD40mYAD\",\"006QF00000LzpRJYAZ\",\"0069N000002uomtQAA\",\"0069N000002xlMLQAY\",\"0066900001NV6ubAAD\",\"0061r00001HJp45AAD\",\"006QF00000uTlUoYAK\",\"006QF00000v0bZqYAI\");\nSELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203\n\nSELECT u.id, u.email, ac.name, a.* FROM activities a\nJOIN users u ON a.user_id = u.id\nJOIN accounts ac ON a.account_id = ac.id\nWHERE\nuuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or\nuuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or\nuuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;\n\nselect * from users where id = 5825;\nSELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;\n\nselect * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;\n19594, 862\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 862 and sa.provider = 'salesforce';\n\nselect * from automated_reports where id = 36;\nselect ar.frequency, r.*, ar.* from automated_report_results r\njoin automated_reports ar on r.report_id = ar.id\nwhere ar.frequency != 'one_off';\n\nselect s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;\nselect * from nudges n where n.activity_search_id\n\nselect * from teams where created_at > '2026-03-09';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;\n\nselect * from users where team_id = 1 and name like '%Lukas%'; # 7160\n\nSELECT * FROM teams WHERE id = 575;\nselect * from opportunities where team_id = 575;\nSELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,\nselect * from opportunities where team_id = 1126;\nSELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,\nselect * from opportunities where team_id = 1125;\nselect * from contacts c\nwhere c.team_id = 882;\n\nSELECT * FROM activities WHERE id = 76822967;\nSELECT * FROM crm_profiles WHERE user_id = 15440;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 555;\nSELECT * FROM crm_configurations WHERE id = 555;\nSELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 581 and sa.provider = 'salesforce';\n\nSELECT * FROM automated_report_results order by id desc;\n\nselect * from features;\nselect * from team_features where feature_id = 40;\n\nselect * from teams where id = 556;\n\nselect * from automated_reports;\nwhere id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , [\"pdf\",\"podcast\"]\nSELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;\nselect * from automated_report_results order by id desc;\nSELECT * FROM automated_report_results WHERE id = 1919;\n\nselect * from automated_report_results WHERE report_id = 54;\n\nselect * from opportunities where id = 7594349;\n\nSELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - jiminnyintegration@lesmills.com\nselect * from playbooks where team_id = 711; # event 226147\nSELECT * FROM playbook_categories WHERE playbook_id = 5515;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';\nSELECT * FROM crm_fields WHERE id = 226147;\nSELECT * FROM crm_field_values WHERE crm_field_id = 226147;\n\nSELECT * FROM crm_configurations WHERE id = 692;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 711 and sa.provider = 'salesforce';\n\nSELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;\n\nselect * from leads;\n\nselect * from calendars;\n\nSELECT\n t.id AS team_id,\n t.name,\n LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain\nFROM teams t\nJOIN users u ON u.team_id = t.id\nJOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'\nLEFT JOIN team_domains td\n ON td.team_id = t.id\n AND td.deleted_at IS NULL\n AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))\nGROUP BY t.id, t.name, calendar_domain\nORDER BY t.name, calendar_domain;\n\nselect * from users u join calendars c on c.user_id = u.id\nwhere u.team_id = 882;\n\n\nselect * from activities where id = 74049485; # team 563 crm 537\nselect * from activities where id = 73272382; # team 563 crm 537\nselect * from activities where id = 64400389; # team 563 crm 537\nselect * from activities where id = 58081273; # team 563 crm 537\nselect * from activities where id = 54520297; # team 563 crm 537\nselect * from participants where activity_id = 58081273;\n\nselect * from activities where crm_configuration_id = 537 and provider = 'aircall'\nand account_id = 19003658 order by updated_at desc;\n\nselect * from contacts where crm_configuration_id = 537 and id = 35957759;\nselect * from accounts where crm_configuration_id = 537 and id = 19003658;\n\nselect * from automated_report_results where id = 1976;\nselect * from automated_reports where id = 583;\nselect * from activity_searches where id = 87714;\nselect * from activity_search_filters where activity_search_id = 87714;\n\nSELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid\nor uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;\n\nSELECT * FROM crm_configurations WHERE provider = 'hubspot';\nselect * from rate_limits;\n\nselect * from automated_report_results where media_type = 'pdf' and status = 2\nand id IN (18, 1872);\nselect * from automated_reports where id = 54;\nSELECT * FROM users WHERE id IN (24623,29443,29613);\n\nSELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
6985417326322133673
|
2218600145176901197
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
40
1
40
64
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE name LIKE '%litify%'; # 1069, 994, 24993
SELECT * FROM users WHERE id = 25061;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 994;
SELECT * FROM crm_profiles WHERE user_id = 25061;
select * from crm_configurations where id = 834;
SELECT * FROM teams WHERE id = 882;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations WHERE provider = 'hubspot' and crm_provider_id = 7270388;
SELECT * FROM contacts where crm_configuration_id = 834;
SELECT * FROM opportunities WHERE team_id = 933
# AND crm_provider_id IN ('20131586060','46017317898','52543911090','53451356564','54101251892','54323768459');
AND id IN (8482561,18352941,19042734,19232139,19445140,19472541);
SELECT * FROM opportunity_contacts
WHERE opportunity_id IN (8482561,18352941,19042734,19232139,19445140,19472541);
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 485; #
SELECT * FROM opportunities WHERE team_id = 933 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
select crm.provider, l.* from leads l join crm_configurations crm on l.crm_configuration_id = crm.id
where crm.provider NOT IN ('salesforce', 'integration-app', 'bullhorn', 'copper')
# and l.converted_at IS NOT NULL
;
# [PASSWORD_DOTS]
SELECT * FROM activities a WHERE type IN ('email-inbound', 'email-outbound')
and opportunity_id IS NULL
order by id desc;
SELECT * FROM teams WHERE id = 604; # 598
SELECT * FROM activities WHERE id = 74410828; # [EMAIL]
SELECT * FROM accounts WHERE id = 20068382;
SELECT * FROM accounts WHERE id = 35186038;
SELECT * FROM contacts WHERE team_id = 852 and updated_at > '2026-01-23 12:30:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 559 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('cb6342b6-a183-401c-b0af-ede92b2ae763') = uuid;
select * from sidekick_settings where team_id = 781;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 26651871; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 7562435;
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8420347; # opflit 2100
SELECT * FROM crm_layouts WHERE crm_configuration_id = 711;
SELECT * FROM activities where crm_configuration_id = 711 and crm_provider_id IS NULL
and is_internal = 0 and status = 'completed'
order by id desc;
SELECT * FROM crm_layout_entities
WHERE crm_layout_id IN (2352, 2353);
;
SELECT * FROM crm_configurations where provider = 'hubspot' and id = 530;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 556 and sa.provider = 'hubspot';
SELECT * FROM activities WHERE uuid_to_bin('c6ca4b22-7738-4563-a95d-b8a9598924ae') = uuid;
SELECT * FROM activities WHERE uuid_to_bin('442abb2b-28bd-4be8-9c25-19e9bf02766d') = uuid;
select * from contacts
where crm_configuration_id = 530
and crm_provider_id = 872252;
select * from activities where crm_configuration_id = 530
and user_id = 14343 and type like '%softphone%'
and created_at between '2026-01-28 15:00:00' and '2026-01-28 15:10:00';
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 25666868; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id = 8646335; # Teya
SELECT * FROM crm_configurations where provider = 'hubspot' and crm_provider_id IN (5933397);
SELECT t.name, t.id, t.owner_id, c.id, c.provider, c.crm_base_url FROM teams t
JOIN crm_configurations c ON t.id = c.team_id
WHERE t.status = 'active';
SELECT * FROM teams where id = 1091;
SELECT * FROM crm_configurations where team_id = 1091;
SELECT * FROM activity_providers where team_id = 1091;
SELECT * FROM activities where crm_configuration_id = 1024 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT * FROM teams WHERE name LIKE '%Leadventure%';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1091 and sa.provider = 'salesforce';
SELECT * FROM teams WHERE name LIKE '%Wilson%'; # 862, 812
SELECT * FROM teams where id = 862;
SELECT * FROM crm_configurations where team_id = 862;
SELECT * FROM activity_providers where team_id = 862;
SELECT * FROM activities where crm_configuration_id = 812 and type IN ('softphone', 'softphone-outbound')
and provider NOT IN ('hubspot', 'aircall')
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by id desc;
SELECT t.id, crm.id, crm.provider, ap.* FROM teams t
join crm_configurations crm on t.id = crm.team_id
join activity_providers ap on t.id = ap.team_id
where t.status = 'active' and ap.is_enabled = 1
and crm.provider = 'hubspot'
and ap.provider NOT IN ('hubspot', 'aircall', 'uploader', 'gong', 'twilio', 'zoom-bot', 'google-meet', 'ms-teams',
'outreach', 'close', 'ringcentral', 'dialpad', 'zoom-phone');
SELECT * FROM teams where id = 1068;
SELECT * FROM crm_configurations where team_id = 1068;
SELECT * FROM activity_providers where team_id = 1068;
SELECT * FROM activities a
where crm_configuration_id = 993 and type IN ('softphone', 'softphone-outbound')
and a.provider NOT IN ('hubspot', 'uploader', 'gong', 'twilio', 'google-meet', 'ms-teams','close'
)
# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'
order by a.id desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1068 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 882; # 933 - GoGlobal , portalId: 6017093
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 933 and updated_at > '2026-02-06 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 933 and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 834; # 882 - AnyVan , portalId: 5468262
SELECT * FROM contacts WHERE crm_configuration_id = 834 and updated_at > '2026-03-30 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and updated_at > '2026-03-04 08:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 882 and sa.provider = 'hubspot';
select * from crm_layouts where crm_configuration_id = 834;
select * from crm_layout_entities where crm_layout_id = 2780;
select * from crm_fields where id IN (321153,321192,321193,321194);
SELECT * FROM opportunities WHERE crm_configuration_id = 834 and id = 10993426;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 988; # 1057 - Teya (543ce4f4-168c-4571-91ea-5b35c253f06f) , portalId: 26651871
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1057 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1057 and sa.provider = 'hubspot';
SELECT * FROM crm_configurations where id = 533; # 559 - Connectd , portalId: 6710988
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 559 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 801; # 852 - Rise Vision , portalId: 2700250
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 852 and updated_at > '2026-02-04 00:00:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 962; # 1034 - evergrowth.io , portalId: 143180990
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1034 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 1037; # 1102 - Jibble , portalId: 6649755
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1102 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 8
SELECT * FROM crm_configurations where id = 1015; # 1049 - Travefy , portalId: 48904401
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1049 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 20
SELECT * FROM crm_configurations where id = 64; # 70 - SalaryFinance , portalId: 3404115
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 70 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 6th last
SELECT * FROM crm_configurations where id = 802; # 853 - Street Group , portalId: 7658438
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 853 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 10
SELECT * FROM crm_configurations where id = 872; # 921 - In Professional Development , portalId: 9238273
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 921 and updated_at > '2026-02-04 12:30:00' order by updated_at desc; # 2
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 550; # 576 - SeedLegals , portalId: 3028661
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 576 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 989; # 1058 - rtaoutdoor.com , portalId: 22371204
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1058 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 896; # 946 - Mintago , portalId: 6621281
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 946 and updated_at > '2026-02-05 14:00:00' order by updated_at desc;
SELECT * FROM crm_configurations where id = 617; # 641 - PCS , portalId: 5244937
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 641 and updated_at > '2026-02-05 14:00:00' order by updated_at desc; # 7th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where id = 649; # 670 - Eventeny , portalId: 4492849
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-18 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 670 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; #
SELECT * FROM crm_configurations where id = 48; # 51 - CleanCloud , portalId: 4373137
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-03-04 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 51 and updated_at > '2026-02-09 08:00:00' order by updated_at desc;
select * from users where team_id = 51; # 7783
SELECT * FROM groups WHERE uuid_to_bin('8a8d2cb6-8b55-4fa3-8b5c-5f0e3d8de59a') = uuid; # 1130
select * from activity_searches where user_id = 7783;
select * from activity_search_filters where activity_search_id IN (32291, 32292);
SELECT asf.activity_search_id, asf.id, asf.value
FROM activity_search_filters asf
WHERE asf.filter = 'group_id'
AND asf.value IN (
SELECT CONCAT(
HEX(SUBSTR(uuid, 5, 4)), '-',
HEX(SUBSTR(uuid, 3, 2)), '-',
HEX(SUBSTR(uuid, 1, 2)), '-',
HEX(SUBSTR(uuid, 9, 2)), '-',
HEX(SUBSTR(uuid, 11))
)
FROM groups
WHERE deleted_at IS NOT NULL
);
SELECT * FROM crm_configurations where id = 272; # 290 - Bonham & Brook , portalId: 5705856
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-05 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 290 and updated_at > '2026-02-09 08:00:00' order by updated_at desc; # 6th
# [PASSWORD_DOTS]
SELECT * FROM crm_configurations where provider = 'hubspot';
SELECT * FROM crm_configurations where id = 1056; # 1119 - Chromatic , portalId: 45602133
SELECT * FROM opportunities WHERE team_id = 1119 and remotely_created_at > '2026-02-01 00:00:00' order by updated_at desc;
SELECT * FROM opportunities WHERE team_id = 1119 and updated_at > '2026-02-09 09:00:00' order by updated_at desc; # null
# [PASSWORD_DOTS]
select * from contacts where crm_provider_id = '003Uu00000ojD4NIAU';
select
cp.*
# DISTINCT t.id
# cp.id, cp.user_id, t.id, cp.crm_configuration_id, cp.contact_fields
FROM crm_profiles cp
JOIN crm_configurations crm on crm.id = cp.crm_configuration_id
JOIN users u on u.id = cp.user_id
JOIN teams t ON t.id = crm.team_id
WHERE crm.provider = 'salesforce' and t.status = 'active'
and cp.archived_at IS NULL and u.deleted_at IS NULL
and t.id NOT IN (1093)
and t.id = 2
and cp.contact_fields IS NULL;
# and c.crm_provider_id = '003Uu00000ojD4NIAU';
SELECT * FROM users WHERE id = 26484;
SELECT * FROM crm_profiles WHERE user_id = 26484;
SELECT * FROM social_accounts WHERE sociable_id = 26484;
SELECT * FROM crm_configurations where provider = 'salesforce';
select * from users where id IN (10022, 10403);
select * from users where team_id IN (526);
select * from teams where id IN (526, 532);
select * from crm_configurations where id IN (500, 516);
select * from crm_profiles where crm_configuration_id IN (500, 516) and user_id IN (10022, 10403);
select * from contacts where crm_configuration_id IN (500, 516) and crm_provider_id = '003Uu00000ojD4NIAU';
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 526 and sa.provider = 'salesforce';
select * from team_settings where team_id IN (526, 532);
select * from users where id IN (22824);
select * from crm_profiles where crm_configuration_id IN (1026);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1093 and sa.provider = 'salesforce';
select * from teams where id = 1099;
select * from users where id = 29643
select * from activity_processing_states;
SELECT * FROM teams where name LIKE '%Fare%'; # 233
SELECT * FROM opportunities where crm_configuration_id = 215
# and crm_provider_id = 'oppo_ogESZf2P50nDrd1nGPvKDXeA6sSaTN5v51Lp4ayVzKR'
;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1088 and sa.provider = 'hubspot';
SELECT * FROM teams order by updated_at DESC
SELECT * FROM crm_configurations WHERE id = 1019; # SimpleConsign 1088 - no social account
select * from crm_configurations where provider = 'pipedrive';
select * from teams where id = 957;
select * from crm_configurations where id = 957;
SELECT * FROM teams WHERE name LIKE '%Prolific%'; # 544, 518, 10743
SELECT * FROM opportunities where crm_configuration_id = 518 order by id desc;
select * from users where team_id = 1; # 26726 - Gabriela Dureva
SELECT * FROM opportunities where user_id = 26726; # 16834447 - Prolific
select * from activities where user_id = 26726 order by id desc;
select * from contacts where crm_configuration_id = 1
and email IN ('[EMAIL]', '[EMAIL]'); # 2094416, 2093620
SELECT * FROM contacts WHERE id = 6284931;
SELECT p.* FROM activities a JOIN participants p ON a.id = p.activity_id
WHERE a.user_id = 26726 and p.lead_id IN (2094416, 2093620) and a.created_at > '2026-01-01 00:00:00' order by p.email;
select * from activities where id IN (75509259,75509261,75509261,75511034,75026464,75517602,75517605);
select * from crm_configurations where id = 1;
43801692-1aeb-32ce-acba-5b80a479701a
44c3c9cf-6f5e-75f3-8179-bc9f75dd2b1b
405975c0-b3d0-7aaa-821f-09d59cae6dd1
4caf848d-4bed-2299-b248-7788d41f9fca
49bedc3f-f196-eef3-89c3-dea6a3b4aa63
43420989-a09d-b8f8-9806-c8bbf7a02aac
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
SELECT * FROM activities WHERE id = 75461988;
SELECT * FROM activities WHERE uuid_to_bin('d6c5052e-e972-49e9-8912-26f2f7d6c5f6') = uuid;
select * from contacts where id = 17900517;
select * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id
where crm.provider != 'salesforce';
select * from users where id = 21047;
SELECT * FROM crm_configurations WHERE id = 892;
SELECT * FROM teams WHERE id = 942;
select * from opportunities where team_id = 942 order by updated_at desc;
select * from contacts where team_id = 942 order by updated_at desc;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 942 and sa.provider = 'hubspot';
SELECT * FROM opportunities where team_id = 1 and crm_provider_id IN ('006Pq00000NeH6XIAV', '006Pq000007z8kdIAA'); # 10697889, 6621430
SELECT * FROM crm_configurations WHERE id = 1;
SELECT * FROM teams WHERE crm_id = 1;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1 and sa.provider = 'salesforce';
select id, user_id, opportunity_fields from crm_profiles where crm_configuration_id = 1
SELECT * FROM opportunities where team_id = 1 order by updated_at desc; # 10697889, 6621430
select * from teams where id = 852;
select * from groups where id = 2286;
select * from sidekick_settings where team_id = 852;
select * from default_activity_types where team_id = 852;
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id AND p.id IS NULL -- no profile
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active' -- team is active
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1 AND u.deleted_at IS NULL
AND u.crm_required = 1
AND u.team_id = 1
ORDER BY u.team_id;
SELECT * FROM crm_profiles cp where cp.crm_configuration_id = 1 and cp.user_id IN (
18481
);
SELECT cc.provider, cc.id, p.id, u.*
FROM users u
LEFT JOIN crm_profiles p ON u.id = p.user_id
INNER JOIN teams t ON u.team_id = t.id AND t.status = 'active'
INNER JOIN crm_configurations cc ON t.crm_id = cc.id
WHERE u.status = 1
AND u.deleted_at IS NULL
AND u.crm_required = 1
# AND u.team_id = 1
AND p.id IS NULL -- Move this condition to WHERE clause
ORDER BY u.team_id;
SELECT * FROM opportunities WHERE id = 20002609;
select * from teams where id = 1122; # Velatir, 29953 - [EMAIL]
select * from crm_configurations where id = 1060;
select * from crm_layouts where crm_configuration_id = 1060;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3596;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 1122 and sa.provider = 'hubspot';
select * from opportunities where team_id = 1122 order by updated_at desc;
select * from crm_field_data where object_type = 'contact';
SELECT * FROM activities WHERE uuid_to_bin('374fc8ed-3315-4c9f-9b25-318b7fd2928f') = uuid; # 76584262
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 248 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles where user_id = 24115; # 005QF000002CswMYAS
SELECT * FROM users where id = 24115;
SELECT * FROM accounts where id = 4002896;
SELECT * FROM teams WHERE name LIKE '%adswerve%';
SELECT * FROM opportunities where crm_configuration_id = 230 AND crm_provider_id IN ("0069N000003GIQ9QAO","0061r000019yGP9AAM","0066900001S2KWlAAN","0066900001TDpj2AAD","0066900001b8uEwAAI","0069N000001rQi0QAE","006QF00000KD40mYAD","006QF00000LzpRJYAZ","0069N000002uomtQAA","0069N000002xlMLQAY","0066900001NV6ubAAD","0061r00001HJp45AAD","006QF00000uTlUoYAK","006QF00000v0bZqYAI");
SELECT * FROM opportunities WHERE crm_configuration_id = 230 AND crm_provider_id = '0069N000003GIQ9QAO'; # 6272203
SELECT u.id, u.email, ac.name, a.* FROM activities a
JOIN users u ON a.user_id = u.id
JOIN accounts ac ON a.account_id = ac.id
WHERE
uuid_to_bin('e3269598-b562-44fb-b5e9-9d2694dc63e0') = a.uuid or
uuid_to_bin('66ddc3ab-4e15-45aa-af0c-248c1eece593') = a.uuid or
uuid_to_bin('826bd328-e1cc-4213-b8d8-572454cacc07') = a.uuid;
select * from users where id = 5825;
SELECT * FROM activities WHERE uuid_to_bin('e56aa2e8-231a-421b-ab1f-cb38ed2bf573') = uuid;
select * from activities where uuid_to_bin('91e13b2f-2d1b-45f8-b1fd-1141b6563782') = uuid;
19594, 862
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 862 and sa.provider = 'salesforce';
select * from automated_reports where id = 36;
select ar.frequency, r.*, ar.* from automated_report_results r
join automated_reports ar on r.report_id = ar.id
where ar.frequency != 'one_off';
select s.* from activity_searches s join users u ON s.user_id = u.id where u.team_id = 882;
select * from nudges n where n.activity_search_id
select * from teams where created_at > '2026-03-09';
SELECT * FROM crm_layouts WHERE crm_configuration_id = 1065; # 1065
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 3617;
select * from users where team_id = 1 and name like '%Lukas%'; # 7160
SELECT * FROM teams WHERE id = 575;
select * from opportunities where team_id = 575;
SELECT * FROM teams WHERE name LIKE '%Integrum ESG%'; # 1126, 1065,
select * from opportunities where team_id = 1126;
SELECT * FROM teams WHERE name LIKE '%Base%'; # 1125, 1063,
select * from opportunities where team_id = 1125;
select * from contacts c
where c.team_id = 882;
SELECT * FROM activities WHERE id = 76822967;
SELECT * FROM crm_profiles WHERE user_id = 15440;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 555;
SELECT * FROM crm_configurations WHERE id = 555;
SELECT * FROM users WHERE id = 15440; # team. 581, gr. 15440, pl. 3911, act. field 162182
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 581 and sa.provider = 'salesforce';
SELECT * FROM automated_report_results order by id desc;
select * from features;
select * from team_features where feature_id = 40;
select * from teams where id = 556;
select * from automated_reports;
where id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044 , ["pdf","podcast"]
SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;
select * from automated_report_results order by id desc;
SELECT * FROM automated_report_results WHERE id = 1919;
select * from automated_report_results WHERE report_id = 54;
select * from opportunities where id = 7594349;
SELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 - [EMAIL]
select * from playbooks where team_id = 711; # event 226147
SELECT * FROM playbook_categories WHERE playbook_id = 5515;
SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';
SELECT * FROM crm_fields WHERE id = 226147;
SELECT * FROM crm_field_values WHERE crm_field_id = 226147;
SELECT * FROM crm_configurations WHERE id = 692;
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 711 and sa.provider = 'salesforce';
SELECT * FROM crm_profiles cp JOIN users u on u.id = cp.user_id WHERE u.team_id = 711;
select * from leads;
select * from calendars;
SELECT
t.id AS team_id,
t.name,
LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1)) AS calendar_domain
FROM teams t
JOIN users u ON u.team_id = t.id
JOIN calendars c ON c.user_id = u.id AND c.status = 'active' AND c.calendar_provider_id LIKE '%@%'
LEFT JOIN team_domains td
ON td.team_id = t.id
AND td.deleted_at IS NULL
AND td.domain = LOWER(SUBSTRING_INDEX(c.calendar_provider_id, '@', -1))
GROUP BY t.id, t.name, calendar_domain
ORDER BY t.name, calendar_domain;
select * from users u join calendars c on c.user_id = u.id
where u.team_id = 882;
select * from activities where id = 74049485; # team 563 crm 537
select * from activities where id = 73272382; # team 563 crm 537
select * from activities where id = 64400389; # team 563 crm 537
select * from activities where id = 58081273; # team 563 crm 537
select * from activities where id = 54520297; # team 563 crm 537
select * from participants where activity_id = 58081273;
select * from activities where crm_configuration_id = 537 and provider = 'aircall'
and account_id = 19003658 order by updated_at desc;
select * from contacts where crm_configuration_id = 537 and id = 35957759;
select * from accounts where crm_configuration_id = 537 and id = 19003658;
select * from automated_report_results where id = 1976;
select * from automated_reports where id = 583;
select * from activity_searches where id = 87714;
select * from activity_search_filters where activity_search_id = 87714;
SELECT * FROM activities WHERE uuid_to_bin('8827f672-202d-4162-9d04-73ff5f0566a9') = uuid
or uuid_to_bin('47842446-af51-4bcb-854f-cc6560290101') = uuid;
SELECT * FROM crm_configurations WHERE provider = 'hubspot';
select * from rate_limits;
select * from automated_report_results where media_type = 'pdf' and status = 2
and id IN (18, 1872);
select * from automated_reports where id = 54;
SELECT * FROM users WHERE id IN (24623,29443,29613);
SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
33562
|
1274
|
24
|
2026-05-13T10:33:34.349064+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668414349_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
40
1
40
64
Previous Highlighted Error...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzing…","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"40","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"40","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"64","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7797430192910716260
|
-7591856686664021237
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
40
1
40
64
Previous Highlighted Error...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
33563
|
1275
|
24
|
2026-05-13T10:33:34.352673+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668414352_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzing…","depth":4,"bounds":{"left":0.3849734,"top":0.10055866,"width":0.019946808,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","depth":4,"bounds":{"left":0.122340426,"top":0.07661612,"width":0.2855718,"height":0.9233839},"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-457998036737617651
|
3937494700968608139
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}...
|
33561
|
NULL
|
NULL
|
NULL
|
|
33564
|
1274
|
25
|
2026-05-13T10:33:35.121329+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668415121_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzing…","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false}]...
|
-457998036737617651
|
3937494700968608139
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}...
|
33562
|
NULL
|
NULL
|
NULL
|
|
33565
|
1275
|
25
|
2026-05-13T10:33:35.095634+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668415095_m2.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
5252240045865077800
|
-8204424741936591930
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
PhostormINavigareCodeLaravelKeractorWindowFV faVsco.js?9 masterProletey(C) DetaultProspectSearciMallooxcontroller.pnpTextkelayservice.onpx© EmailHelper.php(1) FindsProspectintertac© LayoutManager.php(0 MatchDomainRvEmail© OpportunityActivityMa© OpportunitySyncStratec Opportunitysynestrale© ProspectCache.php© ProspectSearchScopec Prospectsearchstrateu Prospectsearchstratec)Providerkeoistrv.ono@ RecordSelector.phr( ResolveCompanvNamC) TimePeriodIterator.ohrImporiInternalKioskv AutomatedRenortsC) ActivitvtvoeServicC) Ask liminnvReportAC) AutomatedRenortsiC) AutomatedRenortsC) DealStadesServicec) RecinienteService re) RenortSort nhr€ ReportSortDirectior(c) KioskService.onpv M Mail>@ Actionsmaffino> @ RepositoriesM Docalvore>C Traitsm ValidatorS(e) RatchCriteria.pho* BatchCriterialnterface© BatchService.php* BatchServicelnterfaceC)EmaillActivivService.oEmailActivitvServicelniC) [EMAIL](1) InboxServiceinterfacel(1) InternetMessagelnterf(c) Mailchanne Service oi© TextRelayService.php1M MeptinaGeneratoNotificationAnalyzing...namespace Jininny services Mallclass TextrelayServicepublic function __construct(){...}* Fetch the latest messages since the last sunclpublic function sync): arraySmailbox = config('jiminny.google_text_user');Sservice = $this->getService($mailbox):SmessageHistory = $this->getHistory(Sservice):SmessageIds = 0]:foreach ($messageHistory as $histories) {smessaces = sniscorles->nessacesaddeatoreach (Smessages as Smessage "SmessageId = Smessage->message->id:SrelayedText = TextRelay::where('email provider id' Smessageld)->firstO:if (SrelayedText === null) {srelavedllext = lextrelav::createu'email provider' => TextRelav:: PROVIDER GSUITE..'email_provider_id' => Smessageld,'status' => TextRelav:: STATUS PROCESSING.Annotate with Git BlameTextRelay(SmessageId, $relayedText))->onQueue(Constants::QUEUE_EMATLS) :Add Bookmark₴8F2Add Mnemonic Bookmark.Coft_Wran1 88;nessadetd.Contiaure Soft Wraps..AnnoarancoContiaure Gutter cons.public function getHistory(GoogleGmail Sservice): array{...}protected function setHistoryPoint(string Stopic, int $historyPoint): Carbon{...}A SF (jiminny@localhost]4 HS_local [jiminny@localhost]& console (PROD] X A console [EU]A console [STAGING] Tx: AutovSELECT * FROM crm_configurations WHERE id = 555;SELE * FROM users WHERE 1d = 15440: # team. 581, or. 15440. pl. 3911, act. Field 162182So jiminny40 41 440 X.04CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,sa.*t.owner_id FROM social_accounts saJOTN usens u on u.id = sa.sociable idlJOIN teams t 1.n<->1: on t.id = u.team_ioWHERE u.team_id = 581 and sa.provider = 'salesforce';SELECT * FROM automated report results order by id desc:select * from features;select * from team_features where feature_id = 40;select * from teamswhere id = 556;select * from automated reports:where id = 54; # 4Fdd41f6-dcF0-30d0-b339-7345381b6044["pdf", "podcast"]SELECT * FROM automated report results WHERE uuid to bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid:automated report results order by 1d descSELEC * FROM automated report results WHERE 10 = 1919select * from automated_report_results WHERE report id = 54;select * from onnortunities where id = 7594349:SELECT * FROM teams WHERE name LIKE '%Les%'; # 711, 692, 16067 -[EMAIL] * from playbooks where team_id = 711; # event 226147SSlECT * CROM nlavhook cateaonies WHEPE nlavhook 1d = 5515•SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event';SELECT * CP0M eom fiolde WHEPE id = 224147•SELECT * FROM crm_field_values WHERE crm_field_id = 226147;SELECT * FROM crm_configurations WHERE id = 692;SELSCTCONCAT(u.id, CASE WHEN u.id = t.owner id THEN ' (owner)' ELSE '• END) AS user id.momosalsa.*,t.owner_id FROM social_accounts saJOIN users u on u.id = sa.sociable idLIOTM toome + 1 ne-df. on + ¿d = n +oom ¿dlWHERE u.team_id = 711 and sa.provider = 'salesforce':SELECT * FROM crm profiles co JOTN users u 1.n<->1: on u.id = co.user id WHERE u.team_id = 711:select * from leads:cascadeTrial Owner Role Sele• suppont Dally • In 1h 21m100% L2• Wed 13 May 13:33:34AskJiminnyReportActivityServiceTest -SMS Failure Email Inve+0 ..Access to file . env is prohibited by .aitiqnore. You can enable access to gitignore files by enabling the setting Allow cascdde access to breignore ritesRead api.php #L1-610Searched GOOGLE_TEXT_RELAY in ~/jiminny/appComplete SMS Email-to-Text Relay Flow1. Trigger PointRoute: POST aoi/sms/relay lin routes/aot, oho line 121 trom webhook.oho) controller: Mar looxcontro ler:: relavo(lines 27-38)D phppublic Tunction relay: kesponsetry{Sthis->relayService->sync():} catch (\Exception $e) (\Sentry:: captureException(Se):throw se:2, Email Svnc (TextRelavService::svnco))• Fetches Gmail history since last sync point (cached)• Creates TextRelay records with STATUS PROCESSING• Dispatches EmailTextRelay jobs for each new email3. Job Processing (EmailTextRelay::handle())Lines 79-159:Anhotry {// 1. Retrieve email from GmailSmessage = Sthis->aetMessade Smal Service, Sthis->message1d):// 2. Extract headers and bodys->getHeaders (Spayload->getHeaders());Sbody = Sthis->getBodySpayload->qetPartso):1/ 2. Validate intearity (checkIntearitv)Ask anvthina (84L)« Code SWF-1.6WN Windsurf Teamo10-20 LITF.Rio 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
33566
|
1274
|
26
|
2026-05-13T10:33:37.027963+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668417027_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Computing annotation for TextRelayService.php
Proj Computing annotation for TextRelayService.php
Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Computing annotation for TextRelayService.php","depth":2,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":2,"bounds":{"left":0.7875,"top":0.0,"width":0.14513889,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzing…","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false}]...
|
-1191687129381149158
|
3937494151086966219
|
visual_change
|
accessibility
|
NULL
|
Computing annotation for TextRelayService.php
Proj Computing annotation for TextRelayService.php
Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
33567
|
1274
|
27
|
2026-05-13T10:33:41.335852+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-13/1778 /Users/lukas/.screenpipe/data/data/2026-05-13/1778668421335_m1.jpg...
|
PhpStorm
|
faVsco.js – TextRelayService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
40
1
40
64
Previous Highlighted Error...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>Some incoming commits are not fetched<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzing…","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Mail;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Jobs\\Mailbox\\EmailTextRelay;\nuse Jiminny\\Models\\TextRelay;\nuse Google\\Service\\Gmail as GoogleGmail;\n\nclass TextRelayService\n{\n public function __construct()\n {\n $credentials = storage_path('text-relay.json');\n\n abort_unless(file_exists($credentials), 422);\n\n putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);\n }\n\n /**\n * Fetch the latest messages since the last sync.\n */\n public function sync(): array\n {\n $mailbox = config('jiminny.google_text_user');\n\n $service = $this->getService($mailbox);\n\n $messageHistory = $this->getHistory($service);\n $messageIds = [];\n\n foreach ($messageHistory as $histories) {\n $messages = $histories->messagesAdded;\n\n foreach ($messages as $message) {\n $messageId = $message->message->id;\n $relayedText = TextRelay::where('email_provider_id', $messageId)->first();\n\n if ($relayedText === null) {\n $relayedText = TextRelay::create([\n 'email_provider' => TextRelay::PROVIDER_GSUITE,\n 'email_provider_id' => $messageId,\n 'status' => TextRelay::STATUS_PROCESSING,\n ]);\n }\n\n $job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);\n\n dispatch($job);\n\n $messageIds[] = $messageId;\n }\n }\n\n return $messageIds;\n }\n\n public function getHistory(GoogleGmail $service): array\n {\n $pageToken = null;\n $topic = config('jiminny.google_text_relay_topic');\n $messages = [];\n $historyId = \\Cache::get($topic);\n\n // If we have no history stored, WatchMailboxEvents must not have run yet :/\n if ($historyId == false) {\n $historyId = $this->refreshHistoryPoint($topic);\n }\n\n $params = [\n 'historyTypes' => 'messageAdded',\n 'startHistoryId' => $historyId,\n ];\n\n do {\n try {\n if ($pageToken) {\n $params['pageToken'] = $pageToken;\n }\n\n $historyResponse = $service->users_history->listUsersHistory(\n config('jiminny.google_text_user'),\n $params\n );\n\n $this->setHistoryPoint($topic, $historyResponse->historyId);\n\n if ($historyResponse->getHistory()) {\n $messages = array_merge($messages, $historyResponse->getHistory());\n $pageToken = $historyResponse->getNextPageToken();\n }\n } catch (\\Exception $e) {\n \\Sentry::captureException($e);\n }\n } while ($pageToken);\n\n return $messages;\n }\n\n protected function setHistoryPoint(string $topic, int $historyPoint): Carbon\n {\n $expiresAt = now()->addDay();\n\n \\Cache::put($topic, $historyPoint, $expiresAt);\n\n return $expiresAt;\n }\n\n public function getService(string $mailbox): GoogleGmail\n {\n $client = new \\Google_Client();\n $client->useApplicationDefaultCredentials();\n $client->addScope(GoogleGmail::GMAIL_MODIFY);\n $client->setAccessType('offline');\n $client->setSubject($mailbox);\n\n return new GoogleGmail($client);\n }\n\n public function refreshHistoryPoint(string $topic): int\n {\n $mailbox = config('jiminny.google_text_user');\n $service = $this->getService($mailbox);\n\n $watchRequest = new GoogleGmail\\WatchRequest();\n $watchRequest->setLabelIds(['INBOX']);\n $watchRequest->setLabelFilterAction('include');\n $watchRequest->setTopicName($topic);\n\n $watchResponse = $service->users->watch($mailbox, $watchRequest);\n\n //$expiryTimestamp = $watchResponse->expiration / 1000;\n $historyPoint = $watchResponse->historyId;\n\n $this->setHistoryPoint($topic, $historyPoint);\n\n return $historyPoint;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"40","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"40","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"64","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7797430192910716260
|
-7591856686664021237
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Mail;
use Carbon\Carbon;
use Jiminny\Component\Queue\Constants;
use Jiminny\Jobs\Mailbox\EmailTextRelay;
use Jiminny\Models\TextRelay;
use Google\Service\Gmail as GoogleGmail;
class TextRelayService
{
public function __construct()
{
$credentials = storage_path('text-relay.json');
abort_unless(file_exists($credentials), 422);
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $credentials);
}
/**
* Fetch the latest messages since the last sync.
*/
public function sync(): array
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$messageHistory = $this->getHistory($service);
$messageIds = [];
foreach ($messageHistory as $histories) {
$messages = $histories->messagesAdded;
foreach ($messages as $message) {
$messageId = $message->message->id;
$relayedText = TextRelay::where('email_provider_id', $messageId)->first();
if ($relayedText === null) {
$relayedText = TextRelay::create([
'email_provider' => TextRelay::PROVIDER_GSUITE,
'email_provider_id' => $messageId,
'status' => TextRelay::STATUS_PROCESSING,
]);
}
$job = (new EmailTextRelay($messageId, $relayedText))->onQueue(Constants::QUEUE_EMAILS);
dispatch($job);
$messageIds[] = $messageId;
}
}
return $messageIds;
}
public function getHistory(GoogleGmail $service): array
{
$pageToken = null;
$topic = config('jiminny.google_text_relay_topic');
$messages = [];
$historyId = \Cache::get($topic);
// If we have no history stored, WatchMailboxEvents must not have run yet :/
if ($historyId == false) {
$historyId = $this->refreshHistoryPoint($topic);
}
$params = [
'historyTypes' => 'messageAdded',
'startHistoryId' => $historyId,
];
do {
try {
if ($pageToken) {
$params['pageToken'] = $pageToken;
}
$historyResponse = $service->users_history->listUsersHistory(
config('jiminny.google_text_user'),
$params
);
$this->setHistoryPoint($topic, $historyResponse->historyId);
if ($historyResponse->getHistory()) {
$messages = array_merge($messages, $historyResponse->getHistory());
$pageToken = $historyResponse->getNextPageToken();
}
} catch (\Exception $e) {
\Sentry::captureException($e);
}
} while ($pageToken);
return $messages;
}
protected function setHistoryPoint(string $topic, int $historyPoint): Carbon
{
$expiresAt = now()->addDay();
\Cache::put($topic, $historyPoint, $expiresAt);
return $expiresAt;
}
public function getService(string $mailbox): GoogleGmail
{
$client = new \Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(GoogleGmail::GMAIL_MODIFY);
$client->setAccessType('offline');
$client->setSubject($mailbox);
return new GoogleGmail($client);
}
public function refreshHistoryPoint(string $topic): int
{
$mailbox = config('jiminny.google_text_user');
$service = $this->getService($mailbox);
$watchRequest = new GoogleGmail\WatchRequest();
$watchRequest->setLabelIds(['INBOX']);
$watchRequest->setLabelFilterAction('include');
$watchRequest->setTopicName($topic);
$watchResponse = $service->users->watch($mailbox, $watchRequest);
//$expiryTimestamp = $watchResponse->expiration / 1000;
$historyPoint = $watchResponse->historyId;
$this->setHistoryPoint($topic, $historyPoint);
return $historyPoint;
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
40
1
40
64
Previous Highlighted Error...
|
33566
|
NULL
|
NULL
|
NULL
|