flowtask 5.8.4__cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flowtask/__init__.py +93 -0
- flowtask/__main__.py +38 -0
- flowtask/bots/__init__.py +6 -0
- flowtask/bots/check.py +93 -0
- flowtask/bots/codebot.py +51 -0
- flowtask/components/ASPX.py +148 -0
- flowtask/components/AddDataset.py +352 -0
- flowtask/components/Amazon.py +523 -0
- flowtask/components/AutoTask.py +314 -0
- flowtask/components/Azure.py +80 -0
- flowtask/components/AzureUsers.py +106 -0
- flowtask/components/BaseAction.py +91 -0
- flowtask/components/BaseLoop.py +198 -0
- flowtask/components/BestBuy.py +800 -0
- flowtask/components/CSVToGCS.py +120 -0
- flowtask/components/CompanyScraper/__init__.py +1 -0
- flowtask/components/CompanyScraper/parsers/__init__.py +6 -0
- flowtask/components/CompanyScraper/parsers/base.py +102 -0
- flowtask/components/CompanyScraper/parsers/explorium.py +192 -0
- flowtask/components/CompanyScraper/parsers/leadiq.py +206 -0
- flowtask/components/CompanyScraper/parsers/rocket.py +133 -0
- flowtask/components/CompanyScraper/parsers/siccode.py +109 -0
- flowtask/components/CompanyScraper/parsers/visualvisitor.py +130 -0
- flowtask/components/CompanyScraper/parsers/zoominfo.py +118 -0
- flowtask/components/CompanyScraper/scrapper.py +1054 -0
- flowtask/components/CopyTo.py +177 -0
- flowtask/components/CopyToBigQuery.py +243 -0
- flowtask/components/CopyToMongoDB.py +291 -0
- flowtask/components/CopyToPg.py +609 -0
- flowtask/components/CopyToRethink.py +207 -0
- flowtask/components/CreateGCSBucket.py +102 -0
- flowtask/components/CreateReport/CreateReport.py +228 -0
- flowtask/components/CreateReport/__init__.py +9 -0
- flowtask/components/CreateReport/charts/__init__.py +15 -0
- flowtask/components/CreateReport/charts/bar.py +51 -0
- flowtask/components/CreateReport/charts/base.py +66 -0
- flowtask/components/CreateReport/charts/pie.py +64 -0
- flowtask/components/CreateReport/utils.py +9 -0
- flowtask/components/CustomerSatisfaction.py +196 -0
- flowtask/components/DataInput.py +200 -0
- flowtask/components/DateList.py +255 -0
- flowtask/components/DbClient.py +163 -0
- flowtask/components/DialPad.py +146 -0
- flowtask/components/DocumentDBQuery.py +200 -0
- flowtask/components/DownloadFrom.py +371 -0
- flowtask/components/DownloadFromD2L.py +113 -0
- flowtask/components/DownloadFromFTP.py +181 -0
- flowtask/components/DownloadFromIMAP.py +315 -0
- flowtask/components/DownloadFromS3.py +198 -0
- flowtask/components/DownloadFromSFTP.py +265 -0
- flowtask/components/DownloadFromSharepoint.py +110 -0
- flowtask/components/DownloadFromSmartSheet.py +114 -0
- flowtask/components/DownloadS3File.py +229 -0
- flowtask/components/Dummy.py +59 -0
- flowtask/components/DuplicatePhoto.py +411 -0
- flowtask/components/EmployeeEvaluation.py +237 -0
- flowtask/components/ExecuteSQL.py +323 -0
- flowtask/components/ExtractHTML.py +178 -0
- flowtask/components/FileBase.py +178 -0
- flowtask/components/FileCopy.py +181 -0
- flowtask/components/FileDelete.py +82 -0
- flowtask/components/FileExists.py +146 -0
- flowtask/components/FileIteratorDelete.py +112 -0
- flowtask/components/FileList.py +194 -0
- flowtask/components/FileOpen.py +75 -0
- flowtask/components/FileRead.py +120 -0
- flowtask/components/FileRename.py +106 -0
- flowtask/components/FilterIf.py +284 -0
- flowtask/components/FilterRows/FilterRows.py +200 -0
- flowtask/components/FilterRows/__init__.py +10 -0
- flowtask/components/FilterRows/functions.py +4 -0
- flowtask/components/GCSToBigQuery.py +103 -0
- flowtask/components/GoogleA4.py +150 -0
- flowtask/components/GoogleGeoCoding.py +344 -0
- flowtask/components/GooglePlaces.py +315 -0
- flowtask/components/GoogleSearch.py +539 -0
- flowtask/components/HTTPClient.py +268 -0
- flowtask/components/ICIMS.py +146 -0
- flowtask/components/IF.py +179 -0
- flowtask/components/IcimsFolderCopy.py +173 -0
- flowtask/components/ImageFeatures/__init__.py +5 -0
- flowtask/components/ImageFeatures/process.py +233 -0
- flowtask/components/IteratorBase.py +251 -0
- flowtask/components/LangchainLoader/__init__.py +5 -0
- flowtask/components/LangchainLoader/loader.py +194 -0
- flowtask/components/LangchainLoader/loaders/__init__.py +22 -0
- flowtask/components/LangchainLoader/loaders/abstract.py +362 -0
- flowtask/components/LangchainLoader/loaders/basepdf.py +50 -0
- flowtask/components/LangchainLoader/loaders/docx.py +91 -0
- flowtask/components/LangchainLoader/loaders/html.py +119 -0
- flowtask/components/LangchainLoader/loaders/pdfblocks.py +146 -0
- flowtask/components/LangchainLoader/loaders/pdfmark.py +79 -0
- flowtask/components/LangchainLoader/loaders/pdftables.py +135 -0
- flowtask/components/LangchainLoader/loaders/qa.py +67 -0
- flowtask/components/LangchainLoader/loaders/txt.py +55 -0
- flowtask/components/LeadIQ.py +650 -0
- flowtask/components/Loop.py +253 -0
- flowtask/components/Lowes.py +334 -0
- flowtask/components/MS365Usage.py +156 -0
- flowtask/components/MSTeamsMessages.py +320 -0
- flowtask/components/MarketClustering.py +1051 -0
- flowtask/components/MergeFiles.py +362 -0
- flowtask/components/MilvusOutput.py +87 -0
- flowtask/components/NearByStores.py +175 -0
- flowtask/components/NetworkNinja/__init__.py +6 -0
- flowtask/components/NetworkNinja/models/__init__.py +52 -0
- flowtask/components/NetworkNinja/models/abstract.py +177 -0
- flowtask/components/NetworkNinja/models/account.py +39 -0
- flowtask/components/NetworkNinja/models/client.py +19 -0
- flowtask/components/NetworkNinja/models/district.py +14 -0
- flowtask/components/NetworkNinja/models/events.py +101 -0
- flowtask/components/NetworkNinja/models/forms.py +499 -0
- flowtask/components/NetworkNinja/models/market.py +16 -0
- flowtask/components/NetworkNinja/models/organization.py +34 -0
- flowtask/components/NetworkNinja/models/photos.py +125 -0
- flowtask/components/NetworkNinja/models/project.py +44 -0
- flowtask/components/NetworkNinja/models/region.py +28 -0
- flowtask/components/NetworkNinja/models/store.py +203 -0
- flowtask/components/NetworkNinja/models/user.py +151 -0
- flowtask/components/NetworkNinja/router.py +854 -0
- flowtask/components/Odoo.py +175 -0
- flowtask/components/OdooInjector.py +192 -0
- flowtask/components/OpenFromXML.py +126 -0
- flowtask/components/OpenWeather.py +41 -0
- flowtask/components/OpenWithBase.py +616 -0
- flowtask/components/OpenWithPandas.py +715 -0
- flowtask/components/PGPDecrypt.py +199 -0
- flowtask/components/PandasIterator.py +187 -0
- flowtask/components/PandasToFile.py +189 -0
- flowtask/components/Paradox.py +339 -0
- flowtask/components/ParamIterator.py +117 -0
- flowtask/components/ParseHTML.py +84 -0
- flowtask/components/PlacerStores.py +249 -0
- flowtask/components/Pokemon.py +507 -0
- flowtask/components/PositiveBot.py +62 -0
- flowtask/components/PowerPointSlide.py +400 -0
- flowtask/components/PrintMessage.py +127 -0
- flowtask/components/ProductCompetitors/__init__.py +5 -0
- flowtask/components/ProductCompetitors/parsers/__init__.py +7 -0
- flowtask/components/ProductCompetitors/parsers/base.py +72 -0
- flowtask/components/ProductCompetitors/parsers/bestbuy.py +86 -0
- flowtask/components/ProductCompetitors/parsers/lowes.py +103 -0
- flowtask/components/ProductCompetitors/scrapper.py +155 -0
- flowtask/components/ProductCompliant.py +169 -0
- flowtask/components/ProductInfo/__init__.py +1 -0
- flowtask/components/ProductInfo/parsers/__init__.py +5 -0
- flowtask/components/ProductInfo/parsers/base.py +83 -0
- flowtask/components/ProductInfo/parsers/brother.py +97 -0
- flowtask/components/ProductInfo/parsers/canon.py +167 -0
- flowtask/components/ProductInfo/parsers/epson.py +118 -0
- flowtask/components/ProductInfo/parsers/hp.py +131 -0
- flowtask/components/ProductInfo/parsers/samsung.py +97 -0
- flowtask/components/ProductInfo/scraper.py +319 -0
- flowtask/components/ProductPricing.py +118 -0
- flowtask/components/QS.py +261 -0
- flowtask/components/QSBase.py +201 -0
- flowtask/components/QueryIterator.py +273 -0
- flowtask/components/QueryToInsert.py +327 -0
- flowtask/components/QueryToPandas.py +432 -0
- flowtask/components/RESTClient.py +195 -0
- flowtask/components/RethinkDBQuery.py +189 -0
- flowtask/components/Rsync.py +74 -0
- flowtask/components/RunSSH.py +59 -0
- flowtask/components/RunShell.py +71 -0
- flowtask/components/SalesForce.py +20 -0
- flowtask/components/SaveImageBank/__init__.py +257 -0
- flowtask/components/SchedulingVisits.py +592 -0
- flowtask/components/ScrapPage.py +216 -0
- flowtask/components/ScrapSearch.py +79 -0
- flowtask/components/SendNotify.py +257 -0
- flowtask/components/SentimentAnalysis.py +694 -0
- flowtask/components/ServiceScrapper/__init__.py +5 -0
- flowtask/components/ServiceScrapper/parsers/__init__.py +1 -0
- flowtask/components/ServiceScrapper/parsers/base.py +94 -0
- flowtask/components/ServiceScrapper/parsers/costco.py +93 -0
- flowtask/components/ServiceScrapper/scrapper.py +199 -0
- flowtask/components/SetVariables.py +156 -0
- flowtask/components/SubTask.py +182 -0
- flowtask/components/SuiteCRM.py +48 -0
- flowtask/components/Switch.py +175 -0
- flowtask/components/TableBase.py +148 -0
- flowtask/components/TableDelete.py +312 -0
- flowtask/components/TableInput.py +143 -0
- flowtask/components/TableOutput/TableOutput.py +384 -0
- flowtask/components/TableOutput/__init__.py +3 -0
- flowtask/components/TableSchema.py +534 -0
- flowtask/components/Target.py +223 -0
- flowtask/components/ThumbnailGenerator.py +156 -0
- flowtask/components/ToPandas.py +67 -0
- flowtask/components/TransformRows/TransformRows.py +507 -0
- flowtask/components/TransformRows/__init__.py +9 -0
- flowtask/components/TransformRows/functions.py +559 -0
- flowtask/components/TransposeRows.py +176 -0
- flowtask/components/UPCDatabase.py +86 -0
- flowtask/components/UnGzip.py +171 -0
- flowtask/components/Uncompress.py +172 -0
- flowtask/components/UniqueRows.py +126 -0
- flowtask/components/Unzip.py +107 -0
- flowtask/components/UpdateOperationalVars.py +147 -0
- flowtask/components/UploadTo.py +299 -0
- flowtask/components/UploadToS3.py +136 -0
- flowtask/components/UploadToSFTP.py +160 -0
- flowtask/components/UploadToSharepoint.py +205 -0
- flowtask/components/UserFunc.py +122 -0
- flowtask/components/VivaTracker.py +140 -0
- flowtask/components/WSDLClient.py +123 -0
- flowtask/components/Wait.py +18 -0
- flowtask/components/Walmart.py +199 -0
- flowtask/components/Workplace.py +134 -0
- flowtask/components/XMLToPandas.py +267 -0
- flowtask/components/Zammad/__init__.py +41 -0
- flowtask/components/Zammad/models.py +0 -0
- flowtask/components/ZoomInfoScraper.py +409 -0
- flowtask/components/__init__.py +104 -0
- flowtask/components/abstract.py +18 -0
- flowtask/components/flow.py +530 -0
- flowtask/components/google.py +335 -0
- flowtask/components/group.py +221 -0
- flowtask/components/py.typed +0 -0
- flowtask/components/reviewscrap.py +132 -0
- flowtask/components/tAutoincrement.py +117 -0
- flowtask/components/tConcat.py +109 -0
- flowtask/components/tExplode.py +119 -0
- flowtask/components/tFilter.py +184 -0
- flowtask/components/tGroup.py +236 -0
- flowtask/components/tJoin.py +270 -0
- flowtask/components/tMap/__init__.py +9 -0
- flowtask/components/tMap/functions.py +54 -0
- flowtask/components/tMap/tMap.py +450 -0
- flowtask/components/tMelt.py +112 -0
- flowtask/components/tMerge.py +114 -0
- flowtask/components/tOrder.py +93 -0
- flowtask/components/tPandas.py +94 -0
- flowtask/components/tPivot.py +71 -0
- flowtask/components/tPluckCols.py +76 -0
- flowtask/components/tUnnest.py +82 -0
- flowtask/components/user.py +401 -0
- flowtask/conf.py +457 -0
- flowtask/download.py +102 -0
- flowtask/events/__init__.py +11 -0
- flowtask/events/events/__init__.py +20 -0
- flowtask/events/events/abstract.py +95 -0
- flowtask/events/events/alerts/__init__.py +362 -0
- flowtask/events/events/alerts/colfunctions.py +131 -0
- flowtask/events/events/alerts/functions.py +158 -0
- flowtask/events/events/dummy.py +12 -0
- flowtask/events/events/exec.py +124 -0
- flowtask/events/events/file/__init__.py +7 -0
- flowtask/events/events/file/base.py +51 -0
- flowtask/events/events/file/copy.py +23 -0
- flowtask/events/events/file/delete.py +16 -0
- flowtask/events/events/interfaces/__init__.py +9 -0
- flowtask/events/events/interfaces/client.py +67 -0
- flowtask/events/events/interfaces/credentials.py +28 -0
- flowtask/events/events/interfaces/notifications.py +58 -0
- flowtask/events/events/jira.py +122 -0
- flowtask/events/events/log.py +26 -0
- flowtask/events/events/logerr.py +52 -0
- flowtask/events/events/notify.py +59 -0
- flowtask/events/events/notify_event.py +160 -0
- flowtask/events/events/publish.py +54 -0
- flowtask/events/events/sendfile.py +104 -0
- flowtask/events/events/task.py +97 -0
- flowtask/events/events/teams.py +98 -0
- flowtask/events/events/webhook.py +58 -0
- flowtask/events/manager.py +287 -0
- flowtask/exceptions.c +39393 -0
- flowtask/exceptions.cpython-310-x86_64-linux-gnu.so +0 -0
- flowtask/extensions/__init__.py +3 -0
- flowtask/extensions/abstract.py +82 -0
- flowtask/extensions/logging/__init__.py +65 -0
- flowtask/hooks/__init__.py +9 -0
- flowtask/hooks/actions/__init__.py +22 -0
- flowtask/hooks/actions/abstract.py +66 -0
- flowtask/hooks/actions/dummy.py +23 -0
- flowtask/hooks/actions/jira.py +74 -0
- flowtask/hooks/actions/rest.py +320 -0
- flowtask/hooks/actions/sampledata.py +37 -0
- flowtask/hooks/actions/sensor.py +23 -0
- flowtask/hooks/actions/task.py +9 -0
- flowtask/hooks/actions/ticket.py +37 -0
- flowtask/hooks/actions/zammad.py +55 -0
- flowtask/hooks/hook.py +62 -0
- flowtask/hooks/models.py +17 -0
- flowtask/hooks/service.py +187 -0
- flowtask/hooks/step.py +91 -0
- flowtask/hooks/types/__init__.py +23 -0
- flowtask/hooks/types/base.py +129 -0
- flowtask/hooks/types/brokers/__init__.py +11 -0
- flowtask/hooks/types/brokers/base.py +54 -0
- flowtask/hooks/types/brokers/mqtt.py +35 -0
- flowtask/hooks/types/brokers/rabbitmq.py +82 -0
- flowtask/hooks/types/brokers/redis.py +83 -0
- flowtask/hooks/types/brokers/sqs.py +44 -0
- flowtask/hooks/types/fs.py +232 -0
- flowtask/hooks/types/http.py +49 -0
- flowtask/hooks/types/imap.py +200 -0
- flowtask/hooks/types/jira.py +279 -0
- flowtask/hooks/types/mail.py +205 -0
- flowtask/hooks/types/postgres.py +98 -0
- flowtask/hooks/types/responses/__init__.py +8 -0
- flowtask/hooks/types/responses/base.py +5 -0
- flowtask/hooks/types/sharepoint.py +288 -0
- flowtask/hooks/types/ssh.py +141 -0
- flowtask/hooks/types/tagged.py +59 -0
- flowtask/hooks/types/upload.py +85 -0
- flowtask/hooks/types/watch.py +71 -0
- flowtask/hooks/types/web.py +36 -0
- flowtask/interfaces/AzureClient.py +137 -0
- flowtask/interfaces/AzureGraph.py +839 -0
- flowtask/interfaces/Boto3Client.py +326 -0
- flowtask/interfaces/DropboxClient.py +173 -0
- flowtask/interfaces/ExcelHandler.py +94 -0
- flowtask/interfaces/FTPClient.py +131 -0
- flowtask/interfaces/GoogleCalendar.py +201 -0
- flowtask/interfaces/GoogleClient.py +133 -0
- flowtask/interfaces/GoogleDrive.py +127 -0
- flowtask/interfaces/GoogleGCS.py +89 -0
- flowtask/interfaces/GoogleGeocoding.py +93 -0
- flowtask/interfaces/GoogleLang.py +114 -0
- flowtask/interfaces/GooglePub.py +61 -0
- flowtask/interfaces/GoogleSheet.py +68 -0
- flowtask/interfaces/IMAPClient.py +137 -0
- flowtask/interfaces/O365Calendar.py +113 -0
- flowtask/interfaces/O365Client.py +220 -0
- flowtask/interfaces/OneDrive.py +284 -0
- flowtask/interfaces/Outlook.py +155 -0
- flowtask/interfaces/ParrotBot.py +130 -0
- flowtask/interfaces/SSHClient.py +378 -0
- flowtask/interfaces/Sharepoint.py +496 -0
- flowtask/interfaces/__init__.py +36 -0
- flowtask/interfaces/azureauth.py +119 -0
- flowtask/interfaces/cache.py +201 -0
- flowtask/interfaces/client.py +82 -0
- flowtask/interfaces/compress.py +525 -0
- flowtask/interfaces/credentials.py +124 -0
- flowtask/interfaces/d2l.py +239 -0
- flowtask/interfaces/databases/__init__.py +5 -0
- flowtask/interfaces/databases/db.py +223 -0
- flowtask/interfaces/databases/documentdb.py +55 -0
- flowtask/interfaces/databases/rethink.py +39 -0
- flowtask/interfaces/dataframes/__init__.py +11 -0
- flowtask/interfaces/dataframes/abstract.py +21 -0
- flowtask/interfaces/dataframes/arrow.py +71 -0
- flowtask/interfaces/dataframes/dt.py +69 -0
- flowtask/interfaces/dataframes/pandas.py +167 -0
- flowtask/interfaces/dataframes/polars.py +60 -0
- flowtask/interfaces/db.py +263 -0
- flowtask/interfaces/env.py +46 -0
- flowtask/interfaces/func.py +137 -0
- flowtask/interfaces/http.py +1780 -0
- flowtask/interfaces/locale.py +40 -0
- flowtask/interfaces/log.py +75 -0
- flowtask/interfaces/mask.py +143 -0
- flowtask/interfaces/notification.py +154 -0
- flowtask/interfaces/playwright.py +339 -0
- flowtask/interfaces/powerpoint.py +368 -0
- flowtask/interfaces/py.typed +0 -0
- flowtask/interfaces/qs.py +376 -0
- flowtask/interfaces/result.py +87 -0
- flowtask/interfaces/selenium_service.py +779 -0
- flowtask/interfaces/smartsheet.py +154 -0
- flowtask/interfaces/stat.py +39 -0
- flowtask/interfaces/task.py +96 -0
- flowtask/interfaces/template.py +118 -0
- flowtask/interfaces/vectorstores/__init__.py +1 -0
- flowtask/interfaces/vectorstores/abstract.py +133 -0
- flowtask/interfaces/vectorstores/milvus.py +669 -0
- flowtask/interfaces/zammad.py +107 -0
- flowtask/models.py +193 -0
- flowtask/parsers/__init__.py +15 -0
- flowtask/parsers/_yaml.c +11978 -0
- flowtask/parsers/_yaml.cpython-310-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/argparser.py +235 -0
- flowtask/parsers/base.c +15155 -0
- flowtask/parsers/base.cpython-310-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/json.c +11968 -0
- flowtask/parsers/json.cpython-310-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/maps.py +49 -0
- flowtask/parsers/toml.c +11968 -0
- flowtask/parsers/toml.cpython-310-x86_64-linux-gnu.so +0 -0
- flowtask/plugins/__init__.py +16 -0
- flowtask/plugins/components/__init__.py +0 -0
- flowtask/plugins/handler/__init__.py +45 -0
- flowtask/plugins/importer.py +31 -0
- flowtask/plugins/sources/__init__.py +0 -0
- flowtask/runner.py +283 -0
- flowtask/scheduler/__init__.py +9 -0
- flowtask/scheduler/functions.py +493 -0
- flowtask/scheduler/handlers/__init__.py +8 -0
- flowtask/scheduler/handlers/manager.py +504 -0
- flowtask/scheduler/handlers/models.py +58 -0
- flowtask/scheduler/handlers/service.py +72 -0
- flowtask/scheduler/notifications.py +65 -0
- flowtask/scheduler/scheduler.py +993 -0
- flowtask/services/__init__.py +0 -0
- flowtask/services/bots/__init__.py +0 -0
- flowtask/services/bots/telegram.py +264 -0
- flowtask/services/files/__init__.py +11 -0
- flowtask/services/files/manager.py +522 -0
- flowtask/services/files/model.py +37 -0
- flowtask/services/files/service.py +767 -0
- flowtask/services/jira/__init__.py +3 -0
- flowtask/services/jira/jira_actions.py +191 -0
- flowtask/services/tasks/__init__.py +13 -0
- flowtask/services/tasks/launcher.py +213 -0
- flowtask/services/tasks/manager.py +323 -0
- flowtask/services/tasks/service.py +275 -0
- flowtask/services/tasks/task_manager.py +376 -0
- flowtask/services/tasks/tasks.py +155 -0
- flowtask/storages/__init__.py +16 -0
- flowtask/storages/exceptions.py +12 -0
- flowtask/storages/files/__init__.py +8 -0
- flowtask/storages/files/abstract.py +29 -0
- flowtask/storages/files/filesystem.py +66 -0
- flowtask/storages/tasks/__init__.py +19 -0
- flowtask/storages/tasks/abstract.py +26 -0
- flowtask/storages/tasks/database.py +33 -0
- flowtask/storages/tasks/filesystem.py +108 -0
- flowtask/storages/tasks/github.py +119 -0
- flowtask/storages/tasks/memory.py +45 -0
- flowtask/storages/tasks/row.py +25 -0
- flowtask/tasks/__init__.py +0 -0
- flowtask/tasks/abstract.py +526 -0
- flowtask/tasks/command.py +118 -0
- flowtask/tasks/pile.py +486 -0
- flowtask/tasks/py.typed +0 -0
- flowtask/tasks/task.py +778 -0
- flowtask/template/__init__.py +161 -0
- flowtask/tests.py +257 -0
- flowtask/types/__init__.py +8 -0
- flowtask/types/typedefs.c +11347 -0
- flowtask/types/typedefs.cpython-310-x86_64-linux-gnu.so +0 -0
- flowtask/utils/__init__.py +24 -0
- flowtask/utils/constants.py +117 -0
- flowtask/utils/encoders.py +21 -0
- flowtask/utils/executor.py +112 -0
- flowtask/utils/functions.cpp +14280 -0
- flowtask/utils/functions.cpython-310-x86_64-linux-gnu.so +0 -0
- flowtask/utils/json.cpp +13349 -0
- flowtask/utils/json.cpython-310-x86_64-linux-gnu.so +0 -0
- flowtask/utils/mail.py +63 -0
- flowtask/utils/parseqs.c +13324 -0
- flowtask/utils/parserqs.cpython-310-x86_64-linux-gnu.so +0 -0
- flowtask/utils/stats.py +308 -0
- flowtask/utils/transformations.py +74 -0
- flowtask/utils/uv.py +12 -0
- flowtask/utils/validators.py +97 -0
- flowtask/version.py +11 -0
- flowtask-5.8.4.dist-info/LICENSE +201 -0
- flowtask-5.8.4.dist-info/METADATA +209 -0
- flowtask-5.8.4.dist-info/RECORD +470 -0
- flowtask-5.8.4.dist-info/WHEEL +6 -0
- flowtask-5.8.4.dist-info/entry_points.txt +3 -0
- flowtask-5.8.4.dist-info/top_level.txt +2 -0
- plugins/components/CreateQR.py +39 -0
- plugins/components/TestComponent.py +28 -0
- plugins/components/Use1.py +13 -0
- plugins/components/Workplace.py +117 -0
- plugins/components/__init__.py +3 -0
- plugins/sources/__init__.py +0 -0
- plugins/sources/get_populartimes.py +78 -0
- plugins/sources/google.py +150 -0
- plugins/sources/hubspot.py +679 -0
- plugins/sources/icims.py +679 -0
- plugins/sources/mobileinsight.py +501 -0
- plugins/sources/newrelic.py +262 -0
- plugins/sources/uap.py +268 -0
- plugins/sources/venu.py +244 -0
- plugins/sources/vocinity.py +314 -0
@@ -0,0 +1,216 @@
|
|
1
|
+
"""
|
2
|
+
Scrapping a Web Page Using Selenium + ChromeDriver + BeautifulSoup.
|
3
|
+
|
4
|
+
|
5
|
+
Example:
|
6
|
+
|
7
|
+
```yaml
|
8
|
+
ScrapPage:
|
9
|
+
url: https://www.consumeraffairs.com/insurance/assurant-phone-insurance.html?page=2#sort=recent
|
10
|
+
rotate_ua: true
|
11
|
+
use_selenium: true
|
12
|
+
use_proxy: true
|
13
|
+
paid_proxy: true
|
14
|
+
as_mobile: false
|
15
|
+
timeout: 60
|
16
|
+
wait_until:
|
17
|
+
- - class_name
|
18
|
+
- js-rvw
|
19
|
+
screenshot:
|
20
|
+
filename: reviews_page.png
|
21
|
+
directory: /home/ubuntu/symbits/ejemplo/screenshots/
|
22
|
+
outputs:
|
23
|
+
- scraped_content
|
24
|
+
- screenshot_path
|
25
|
+
```
|
26
|
+
|
27
|
+
"""
|
28
|
+
import asyncio
|
29
|
+
from collections.abc import Callable
|
30
|
+
from pathlib import Path, PurePath
|
31
|
+
from typing import Optional
|
32
|
+
from navconfig import BASE_DIR
|
33
|
+
# Internals
|
34
|
+
from ..exceptions import (
|
35
|
+
ComponentError,
|
36
|
+
DataNotFound,
|
37
|
+
TimeOutError
|
38
|
+
)
|
39
|
+
from .flow import FlowComponent
|
40
|
+
from ..interfaces import HTTPService, SeleniumService
|
41
|
+
|
42
|
+
|
43
|
+
class ScrapPage(SeleniumService, HTTPService, FlowComponent):
|
44
|
+
"""ScrapPage.
|
45
|
+
Scrapping a Web Page using Selenium.
|
46
|
+
"""
|
47
|
+
def __init__(
|
48
|
+
self,
|
49
|
+
loop: asyncio.AbstractEventLoop = None,
|
50
|
+
job: Callable = None,
|
51
|
+
stat: Callable = None,
|
52
|
+
**kwargs,
|
53
|
+
):
|
54
|
+
"""Init Method."""
|
55
|
+
self.url: str = kwargs.get("url", None)
|
56
|
+
self.urls: list = kwargs.get('urls', [])
|
57
|
+
self.find_elements: list = kwargs.get('find_elements', [])
|
58
|
+
self.rotate_ua: bool = True
|
59
|
+
kwargs['rotate_ua'] = True # Forcing UA Rotation.
|
60
|
+
self.use_selenium: bool = kwargs.pop(
|
61
|
+
"use_selenium",
|
62
|
+
False
|
63
|
+
)
|
64
|
+
# URL Function: generate the URL based on a function:
|
65
|
+
self.url_function: str = kwargs.pop('url_function', None)
|
66
|
+
# Return the Driver (avoid closing the Driver at the end of the process).
|
67
|
+
self.return_driver: bool = kwargs.pop('return_driver', False)
|
68
|
+
super(ScrapPage, self).__init__(
|
69
|
+
loop=loop,
|
70
|
+
job=job,
|
71
|
+
stat=stat,
|
72
|
+
**kwargs
|
73
|
+
)
|
74
|
+
# Fix the Headers for Scrapping:
|
75
|
+
self.headers: dict = {
|
76
|
+
"Host": self.extract_host(self.url),
|
77
|
+
**self.headers
|
78
|
+
}
|
79
|
+
|
80
|
+
async def start(self, **kwargs) -> bool:
|
81
|
+
await super(ScrapPage, self).start(**kwargs)
|
82
|
+
if self.use_selenium is True:
|
83
|
+
await self.get_driver()
|
84
|
+
# Generate a URL based on a URL Function:
|
85
|
+
if self.url_function:
|
86
|
+
fn = getattr(self, self.url_function, None)
|
87
|
+
if fn:
|
88
|
+
self.url = await fn()
|
89
|
+
return True
|
90
|
+
|
91
|
+
async def close(self, **kwargs) -> bool:
|
92
|
+
if self.use_selenium is True:
|
93
|
+
if self.return_driver is False:
|
94
|
+
self.close_driver()
|
95
|
+
return True
|
96
|
+
|
97
|
+
async def run_http(self):
|
98
|
+
"""Run the Scrapping Tool Using HTTPx."""
|
99
|
+
result, error = await self.session(
|
100
|
+
url=self.url,
|
101
|
+
method=self.method,
|
102
|
+
headers=self.headers,
|
103
|
+
cookies=self.cookies,
|
104
|
+
follow_redirects=True,
|
105
|
+
use_proxy=self.use_proxy
|
106
|
+
)
|
107
|
+
if error:
|
108
|
+
raise ComponentError(
|
109
|
+
f"Error running HTTP: {error}"
|
110
|
+
)
|
111
|
+
if not result:
|
112
|
+
raise DataNotFound(
|
113
|
+
f"No content on URL {self.url}"
|
114
|
+
)
|
115
|
+
return result
|
116
|
+
|
117
|
+
async def run_selenium(self):
|
118
|
+
"""Run the Scrapping Tool Using Selenium."""
|
119
|
+
try:
|
120
|
+
await self.get_page(self.url, self.cookies)
|
121
|
+
found_elements = None
|
122
|
+
file = None
|
123
|
+
content = None
|
124
|
+
if self.inner_tag:
|
125
|
+
content = self.driver().find_element(*self.inner_tag).get_attribute('innerHTML')
|
126
|
+
else:
|
127
|
+
content = self.driver().page_source
|
128
|
+
if hasattr(self, 'screenshot'):
|
129
|
+
# capture an screenshot from the page and save it (and returning as binary as well)
|
130
|
+
filename = self.screenshot.get('filename', 'screenshot.png')
|
131
|
+
directory = Path(self.screenshot.get(
|
132
|
+
'directory', BASE_DIR.joinpath('static', 'images', 'screenshots')
|
133
|
+
))
|
134
|
+
if not directory.is_absolute():
|
135
|
+
directory = BASE_DIR.joinpath('static', 'images', directory)
|
136
|
+
if directory.exists() is False:
|
137
|
+
directory.mkdir(parents=True, exist_ok=True)
|
138
|
+
# Take the screenshot
|
139
|
+
file = directory.joinpath(filename)
|
140
|
+
self.save_screenshot(str(file))
|
141
|
+
if self.find_elements:
|
142
|
+
# For the main content, fallback to page_source:
|
143
|
+
content = self.driver().page_source
|
144
|
+
try:
|
145
|
+
print('FINDING > ', self.find_elements)
|
146
|
+
elements = self.driver().find_elements(*self.find_elements)
|
147
|
+
found_elements = elements
|
148
|
+
except Exception as exc:
|
149
|
+
# Log the exception as a warning instead of raising it
|
150
|
+
self.logger.warning(
|
151
|
+
f"Unable to find elements with locator {self.find_elements}: {exc}"
|
152
|
+
)
|
153
|
+
found_elements = []
|
154
|
+
# Return the content of the page.
|
155
|
+
return content, file, found_elements
|
156
|
+
except (TimeOutError, ComponentError):
|
157
|
+
raise
|
158
|
+
except Exception as exc:
|
159
|
+
raise ComponentError(
|
160
|
+
f"Error running Selenium: {exc}"
|
161
|
+
)
|
162
|
+
|
163
|
+
def _build_result_content(self, content: str, screenshot: PurePath, found_elements: Optional[list] = None) -> dict:
|
164
|
+
"""Build the Result Content."""
|
165
|
+
soup = self.get_soup(content)
|
166
|
+
_xml, _html = self.get_etree(content)
|
167
|
+
result = {
|
168
|
+
"raw": content,
|
169
|
+
"soup": soup,
|
170
|
+
"html": _html,
|
171
|
+
"xml": _xml,
|
172
|
+
"screenshot": screenshot
|
173
|
+
}
|
174
|
+
if found_elements is not None:
|
175
|
+
result["found_elements"] = found_elements
|
176
|
+
return result
|
177
|
+
|
178
|
+
async def run(self):
|
179
|
+
"""Run the Scrapping Tool."""
|
180
|
+
self._result = None
|
181
|
+
screenshot = None
|
182
|
+
found_elements = None
|
183
|
+
try:
|
184
|
+
if self.use_selenium is True:
|
185
|
+
if self.urls:
|
186
|
+
results = []
|
187
|
+
for url in self.urls:
|
188
|
+
self.url = url
|
189
|
+
self.headers['Host'] = self.extract_host(url)
|
190
|
+
self.headers['Referer'] = url
|
191
|
+
content, screenshot, found_elements = await self.run_selenium()
|
192
|
+
result = self._build_result_content(content, screenshot, found_elements)
|
193
|
+
results.append(
|
194
|
+
{"url": url, "content": result}
|
195
|
+
)
|
196
|
+
self._result = results
|
197
|
+
return results
|
198
|
+
else:
|
199
|
+
content, screenshot, found_elements = await self.run_selenium()
|
200
|
+
else:
|
201
|
+
content = await self.run_http()
|
202
|
+
if not content:
|
203
|
+
raise DataNotFound(
|
204
|
+
f"No content on URL {self.url}"
|
205
|
+
)
|
206
|
+
except ComponentError:
|
207
|
+
raise
|
208
|
+
except Exception as exc:
|
209
|
+
raise ComponentError(
|
210
|
+
f"Error running ScrapPage: {exc}"
|
211
|
+
)
|
212
|
+
if self.return_driver is True:
|
213
|
+
self._result = self.driver()
|
214
|
+
else:
|
215
|
+
self._result = self._build_result_content(content, screenshot, found_elements)
|
216
|
+
return self._result
|
@@ -0,0 +1,79 @@
|
|
1
|
+
from bs4 import BeautifulSoup
|
2
|
+
from .ScrapPage import ScrapPage
|
3
|
+
from ..exceptions import ComponentError
|
4
|
+
|
5
|
+
|
6
|
+
class ScrapSearch(ScrapPage):
|
7
|
+
"""Search by a Product, retrieve the URL (based on rules) and scrap the page."""
|
8
|
+
# TODO: Idea is for making the search functions pluggable.
|
9
|
+
def __init__(self, **kwargs):
|
10
|
+
self.find_element: tuple = kwargs.pop('find_element', ('li', {'class': ['sku-item']}))
|
11
|
+
super().__init__(**kwargs)
|
12
|
+
self.product_sku: str = kwargs.pop('product_sku', None)
|
13
|
+
self.brand: str = kwargs.pop('brand', None)
|
14
|
+
|
15
|
+
async def _bby_products(self):
|
16
|
+
front_url = "https://www.bestbuy.com/site/searchpage.jsp?cp="
|
17
|
+
middle_url = "&searchType=search&st="
|
18
|
+
page_count = 1
|
19
|
+
# TODO: Get the Brand and Model from the Component.
|
20
|
+
model = self.product_sku
|
21
|
+
brand = self.brand
|
22
|
+
search_term = f'{brand}%20{model}'
|
23
|
+
end_url = "&_dyncharset=UTF-8&id=pcat17071&type=page&sc=Global&nrp=&sp=&qp=&list=n&af=true&iht=y&usc=All%20Categories&ks=960&keys=keys" # noqa
|
24
|
+
url = front_url + str(page_count) + middle_url + search_term + end_url
|
25
|
+
print('SEARCH URL: ', url)
|
26
|
+
return url
|
27
|
+
|
28
|
+
async def _search_bby_products(self, content: str) -> str:
|
29
|
+
soup = BeautifulSoup(content, 'html.parser')
|
30
|
+
# Find all elements with class "sku-item"
|
31
|
+
product_items = soup.find_all(*self.find_element)
|
32
|
+
# Iterate over each product item
|
33
|
+
url = None
|
34
|
+
for item in product_items:
|
35
|
+
# Get the "data-sku-id" attribute
|
36
|
+
sku_id = item.get("data-sku-id")
|
37
|
+
# Check if the SKU ID matches your target SKU ID
|
38
|
+
if sku_id == self.product_sku:
|
39
|
+
print(f"Found matching SKU ID: {sku_id}")
|
40
|
+
# Now look for the child with class "sku-title"
|
41
|
+
pd = item.find('h4', {'class': ['sku-title']})
|
42
|
+
anchor = pd.a
|
43
|
+
url = "https://www.bestbuy.com{url}".format(
|
44
|
+
url=anchor['href']
|
45
|
+
)
|
46
|
+
print('Product URL: ', url)
|
47
|
+
return url
|
48
|
+
|
49
|
+
async def run(self):
|
50
|
+
# Run works differently for ScrapPage:
|
51
|
+
self._result = None
|
52
|
+
screenshot = None
|
53
|
+
# 1. Get the Product List URL
|
54
|
+
fn = getattr(self, f"_{self.url_function}", None)
|
55
|
+
if not fn:
|
56
|
+
raise ComponentError(
|
57
|
+
f"Function {self.url_function} not found."
|
58
|
+
)
|
59
|
+
url = await fn()
|
60
|
+
if self.use_selenium is True:
|
61
|
+
await self.get_page(url, self.cookies)
|
62
|
+
content = self.driver().page_source
|
63
|
+
# 2. Search the Product
|
64
|
+
search_fn = getattr(self, f"_search_{self.url_function}", None)
|
65
|
+
if search_fn:
|
66
|
+
url = await search_fn(content)
|
67
|
+
if url:
|
68
|
+
# 3. Get the URL
|
69
|
+
self.url = url
|
70
|
+
# 4. Run the Scrapping Tool to extract the Product page.
|
71
|
+
content, screenshot = await self.run_selenium()
|
72
|
+
if self.return_driver is True:
|
73
|
+
self._result = self.driver()
|
74
|
+
else:
|
75
|
+
self._result = self._build_result_content(
|
76
|
+
content,
|
77
|
+
screenshot
|
78
|
+
)
|
79
|
+
return self._result
|
@@ -0,0 +1,257 @@
|
|
1
|
+
import os
|
2
|
+
import asyncio
|
3
|
+
from typing import Dict, List
|
4
|
+
from collections.abc import Callable, Iterable
|
5
|
+
from pathlib import Path
|
6
|
+
from navconfig.logging import logging
|
7
|
+
from notify import Notify
|
8
|
+
from notify.models import Actor
|
9
|
+
from ..exceptions import ComponentError, FileNotFound
|
10
|
+
from .flow import FlowComponent
|
11
|
+
from ..interfaces import DBSupport
|
12
|
+
|
13
|
+
|
14
|
+
def expand_path(filename: str) -> Iterable[Path]:
|
15
|
+
p = Path(filename)
|
16
|
+
return Path(p.parent).expanduser().glob(p.name)
|
17
|
+
|
18
|
+
|
19
|
+
class SendNotify(DBSupport, FlowComponent):
|
20
|
+
"""
|
21
|
+
SendNotify
|
22
|
+
|
23
|
+
Overview
|
24
|
+
|
25
|
+
The SendNotify class is a component for sending notifications to a list of recipients via various
|
26
|
+
channels (e.g., email) using the Notify component. It supports adding attachments, templating messages
|
27
|
+
with masked variables, and utilizing custom credentials for authentication.
|
28
|
+
|
29
|
+
.. table:: Properties
|
30
|
+
:widths: auto
|
31
|
+
|
32
|
+
+----------------+----------+-----------+----------------------------------------------------------------------+
|
33
|
+
| Name | Required | Summary |
|
34
|
+
+----------------+----------+-----------+----------------------------------------------------------------------+
|
35
|
+
| via | Yes | The method for sending the notification, e.g., "email". |
|
36
|
+
+----------------+----------+-----------+----------------------------------------------------------------------+
|
37
|
+
| account | Yes | A dictionary with server credentials, including `host`, `port`, |
|
38
|
+
| | | `username`, and `password`. |
|
39
|
+
+----------------+----------+-----------+----------------------------------------------------------------------+
|
40
|
+
| recipients | Yes | List of dictionaries with target user details for notification. |
|
41
|
+
+----------------+----------+-----------+----------------------------------------------------------------------+
|
42
|
+
| list | No | Optional mailing list name for retrieving recipients from the database. |
|
43
|
+
+----------------+----------+-----------+----------------------------------------------------------------------+
|
44
|
+
| attachments | No | List of file paths for attachments to include in the notification. |
|
45
|
+
+----------------+----------+-----------+----------------------------------------------------------------------+
|
46
|
+
| message | Yes | Dictionary with the notification message content, supporting template variables. |
|
47
|
+
+----------------+----------+-----------+----------------------------------------------------------------------+
|
48
|
+
|
49
|
+
Returns
|
50
|
+
|
51
|
+
This component returns the input data after sending the notification. Metrics are recorded for each
|
52
|
+
successful send, with details on recipients and the message content. If any specified attachment file
|
53
|
+
is missing, a `FileNotFound` exception is raised. If there are errors in setting up or sending the
|
54
|
+
notification, a `ComponentError` is raised with descriptive messages.
|
55
|
+
|
56
|
+
|
57
|
+
Example:
|
58
|
+
|
59
|
+
```yaml
|
60
|
+
SendNotify:
|
61
|
+
via: email
|
62
|
+
account:
|
63
|
+
hostname: NAVIGATOR_ALERT_EMAIL_HOSTNAME
|
64
|
+
port: NAVIGATOR_ALERT_EMAIL_PORT
|
65
|
+
password: NAVIGATOR_ALERT_EMAIL_PASSWORD
|
66
|
+
username: NAVIGATOR_ALERT_EMAIL_USERNAME
|
67
|
+
attachments:
|
68
|
+
- /home/ubuntu/symbits/bose/files/report/troc_open_tickets_{today}.csv
|
69
|
+
masks:
|
70
|
+
'{today}':
|
71
|
+
- today
|
72
|
+
- mask: '%Y-%m-%d'
|
73
|
+
'{yesterday}':
|
74
|
+
- yesterday
|
75
|
+
- mask: '%Y-%m-%d'
|
76
|
+
'{human-today}':
|
77
|
+
- today
|
78
|
+
- mask: '%m/%d/%Y'
|
79
|
+
'{human-yesterday}':
|
80
|
+
- yesterday
|
81
|
+
- mask: '%m/%d/%Y'
|
82
|
+
'#today-timestamp#':
|
83
|
+
- current_timestamp
|
84
|
+
- tz: America/New_York
|
85
|
+
recipients:
|
86
|
+
- name: Carlos Rivero
|
87
|
+
account:
|
88
|
+
address: crivero@trocglobal.com
|
89
|
+
- name: Arturo Martinez
|
90
|
+
account:
|
91
|
+
address: amartinez@trocglobal.com
|
92
|
+
- name: Jhoanir Torres
|
93
|
+
account:
|
94
|
+
address: jhtorres@trocglobal.com
|
95
|
+
- name: Steven Greenstein
|
96
|
+
account:
|
97
|
+
address: sgreenstein@trocglobal.com
|
98
|
+
- name: Sabra Pierre
|
99
|
+
account:
|
100
|
+
address: spierre1@trocglobal.com
|
101
|
+
- name: Daniel McGee
|
102
|
+
account:
|
103
|
+
address: dmcgee@trocglobal.com
|
104
|
+
- name: Kile Harris
|
105
|
+
account:
|
106
|
+
address: kharris10@trocglobal.com
|
107
|
+
- name: Gerardo Espinoza
|
108
|
+
account:
|
109
|
+
address: gespinoza@trocglobal.com
|
110
|
+
- name: Christopher Harmon
|
111
|
+
account:
|
112
|
+
address: charmon@trocglobal.com
|
113
|
+
message:
|
114
|
+
subject: T-ROC BOSE Break&Fix Open Tickets ({human-today})
|
115
|
+
message_content: Please find attached the report generated on {human-today}.This
|
116
|
+
is an automated message - please do not reply directly to this email.
|
117
|
+
template: email_custom_report.html
|
118
|
+
clientName: Bose
|
119
|
+
dateGenerated: '{human-today}'
|
120
|
+
created_at: '#today-timestamp#'
|
121
|
+
```
|
122
|
+
|
123
|
+
""" # noqa
|
124
|
+
|
125
|
+
_credentials: dict = {
|
126
|
+
"hostname": str,
|
127
|
+
"port": int,
|
128
|
+
"username": str,
|
129
|
+
"password": str,
|
130
|
+
}
|
131
|
+
|
132
|
+
def __init__(
|
133
|
+
self,
|
134
|
+
loop: asyncio.AbstractEventLoop = None,
|
135
|
+
job: Callable = None,
|
136
|
+
stat: Callable = None,
|
137
|
+
**kwargs,
|
138
|
+
):
|
139
|
+
"""Init Method."""
|
140
|
+
self.attachments: List = []
|
141
|
+
self.list_attachment: List = []
|
142
|
+
self.notify: Callable = None
|
143
|
+
self.recipients: List = []
|
144
|
+
self._recipients: List = []
|
145
|
+
self.via: str = "email"
|
146
|
+
self.message: Dict = {}
|
147
|
+
# renaming account to credentials in kwargs:
|
148
|
+
if "account" in kwargs:
|
149
|
+
kwargs["credentials"] = kwargs.pop("account")
|
150
|
+
super(SendNotify, self).__init__(
|
151
|
+
loop=loop,
|
152
|
+
job=job,
|
153
|
+
stat=stat,
|
154
|
+
**kwargs
|
155
|
+
)
|
156
|
+
|
157
|
+
def status_sent(self, recipient, message, result, *args, **kwargs):
|
158
|
+
print(
|
159
|
+
f"Notification with status {result!s} to {recipient.account!s}"
|
160
|
+
)
|
161
|
+
logging.info(f"Notification with status {result!s} to {recipient.account!s}")
|
162
|
+
status = {"recipient": recipient, "result": result}
|
163
|
+
self.add_metric("Sent", status)
|
164
|
+
|
165
|
+
async def start(self, **kwargs):
|
166
|
+
if self.previous:
|
167
|
+
self.data = self.input
|
168
|
+
await super().start(**kwargs)
|
169
|
+
self.processing_credentials()
|
170
|
+
# TODO: generate file from dataset (dataframe)
|
171
|
+
# using mailing list:
|
172
|
+
if hasattr(self, "list"):
|
173
|
+
# getting the mailing list:
|
174
|
+
lst = self.list
|
175
|
+
sql = f"SELECT * FROM troc.get_mailing_list('{lst!s}')"
|
176
|
+
try:
|
177
|
+
connection = self.get_connection()
|
178
|
+
async with await connection.connection() as conn:
|
179
|
+
result, error = await conn.query(sql)
|
180
|
+
if error:
|
181
|
+
raise ComponentError(
|
182
|
+
f"CreateReport: Error on Recipients: {error!s}."
|
183
|
+
)
|
184
|
+
for r in result:
|
185
|
+
actor = Actor(**dict(r))
|
186
|
+
self._recipients.append(actor)
|
187
|
+
except Exception as err:
|
188
|
+
logging.exception(err)
|
189
|
+
else:
|
190
|
+
# determine the recipients:
|
191
|
+
try:
|
192
|
+
self._recipients = [Actor(**user) for user in self.recipients]
|
193
|
+
except Exception as err:
|
194
|
+
raise ComponentError(f"Error formatting Recipients: {err}") from err
|
195
|
+
if not self._recipients:
|
196
|
+
raise ComponentError("SendNotify: Invalid Number of Recipients.")
|
197
|
+
if hasattr(self, "masks"):
|
198
|
+
for _, attach in enumerate(self.attachments):
|
199
|
+
attachment = self.mask_replacement(attach)
|
200
|
+
# resolve filenames:
|
201
|
+
files = expand_path(attachment)
|
202
|
+
for file in files:
|
203
|
+
self.list_attachment.append(file)
|
204
|
+
# Mask transform of message
|
205
|
+
for key, value in self.message.items():
|
206
|
+
self.message[key] = self.mask_replacement(value)
|
207
|
+
self._logger.notice(
|
208
|
+
f"Variable: {key} = {self.message[key]}"
|
209
|
+
)
|
210
|
+
# Verify if file exists
|
211
|
+
for file in self.list_attachment:
|
212
|
+
if not file.exists():
|
213
|
+
raise FileNotFound(
|
214
|
+
f"File doesn't exists: {file}"
|
215
|
+
)
|
216
|
+
return True
|
217
|
+
|
218
|
+
async def close(self):
|
219
|
+
if self.notify:
|
220
|
+
try:
|
221
|
+
await self.notify.close()
|
222
|
+
except Exception as err:
|
223
|
+
print(err)
|
224
|
+
|
225
|
+
async def run(self):
|
226
|
+
"""
|
227
|
+
Running the Notification over all recipients.
|
228
|
+
"""
|
229
|
+
self._result = self.data # by-pass override data (pass-through)
|
230
|
+
if self.data is not None:
|
231
|
+
if isinstance(self.data, list):
|
232
|
+
self.message['filenames'] = self.data
|
233
|
+
elif isinstance(self.data, dict):
|
234
|
+
self.message.update(self.data)
|
235
|
+
|
236
|
+
# create the notify component
|
237
|
+
account = {**self.credentials}
|
238
|
+
|
239
|
+
try:
|
240
|
+
self.notify = Notify(self.via, loop=self._loop, **account)
|
241
|
+
self.notify.sent = self.status_sent
|
242
|
+
except Exception as err:
|
243
|
+
raise ComponentError(f"Error Creating Notification App: {err}") from err
|
244
|
+
try:
|
245
|
+
result = await self.notify.send(
|
246
|
+
recipient=self._recipients,
|
247
|
+
attachments=self.list_attachment,
|
248
|
+
**self.message,
|
249
|
+
)
|
250
|
+
logging.debug(f"Notification Status: {result}")
|
251
|
+
# add metric:
|
252
|
+
self.add_metric("Notification", self.message)
|
253
|
+
except Exception as err:
|
254
|
+
raise ComponentError(f"SendNotify Error: {err}") from err
|
255
|
+
if self.data is None:
|
256
|
+
return True
|
257
|
+
return self._result
|