flowtask 5.8.4__cp312-cp312-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-312-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-312-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/argparser.py +235 -0
- flowtask/parsers/base.c +15155 -0
- flowtask/parsers/base.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/json.c +11968 -0
- flowtask/parsers/json.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/parsers/maps.py +49 -0
- flowtask/parsers/toml.c +11968 -0
- flowtask/parsers/toml.cpython-312-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-312-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-312-x86_64-linux-gnu.so +0 -0
- flowtask/utils/json.cpp +13349 -0
- flowtask/utils/json.cpython-312-x86_64-linux-gnu.so +0 -0
- flowtask/utils/mail.py +63 -0
- flowtask/utils/parseqs.c +13324 -0
- flowtask/utils/parserqs.cpython-312-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,54 @@
|
|
1
|
+
import asyncio
|
2
|
+
from typing import Optional, Any
|
3
|
+
from aiohttp import web
|
4
|
+
from abc import abstractmethod
|
5
|
+
from ..base import BaseTrigger
|
6
|
+
|
7
|
+
class BaseMQTrigger(BaseTrigger):
|
8
|
+
def __init__(self, *args, actions: list = None, **kwargs):
|
9
|
+
super().__init__(*args, actions=actions, **kwargs)
|
10
|
+
self.consumer_task: Optional[asyncio.Task] = None
|
11
|
+
self._connection = None # To be set in subclass
|
12
|
+
self._queue_name = kwargs.get('queue_name', 'default_queue')
|
13
|
+
|
14
|
+
@abstractmethod
|
15
|
+
async def connect(self):
|
16
|
+
"""Establish the connection."""
|
17
|
+
pass
|
18
|
+
|
19
|
+
@abstractmethod
|
20
|
+
async def disconnect(self):
|
21
|
+
"""Disconnect the connection."""
|
22
|
+
pass
|
23
|
+
|
24
|
+
async def on_startup(self, app):
|
25
|
+
self._logger.info(
|
26
|
+
f"Starting MQ Broker {self.__class__.__name__}"
|
27
|
+
)
|
28
|
+
await self.connect()
|
29
|
+
self.consumer_task = asyncio.create_task(self.start_consuming())
|
30
|
+
|
31
|
+
async def on_shutdown(self, app):
|
32
|
+
self._logger.info(
|
33
|
+
f"Shutting down MQ Broker {self.__class__.__name__}"
|
34
|
+
)
|
35
|
+
if self.consumer_task:
|
36
|
+
self.consumer_task.cancel()
|
37
|
+
try:
|
38
|
+
await self.consumer_task
|
39
|
+
except asyncio.CancelledError:
|
40
|
+
self._logger.info("Consumer task cancelled.")
|
41
|
+
self.consumer_task = None
|
42
|
+
await self.disconnect()
|
43
|
+
|
44
|
+
@abstractmethod
|
45
|
+
async def start_consuming(self):
|
46
|
+
"""Start consuming messages."""
|
47
|
+
pass
|
48
|
+
|
49
|
+
def setup(self, app: web.Application):
|
50
|
+
super().setup(app)
|
51
|
+
|
52
|
+
@abstractmethod
|
53
|
+
async def _consumer_callback(self, *args, **kwargs) -> None:
|
54
|
+
pass
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import asyncio
|
2
|
+
from gmqtt import Client as MQTTClient
|
3
|
+
from ..base import BaseTrigger
|
4
|
+
|
5
|
+
class MQTTTrigger(BaseTrigger):
|
6
|
+
def __init__(self, *args, broker_url: str, topics: list, **kwargs):
|
7
|
+
super().__init__(*args, **kwargs)
|
8
|
+
self.broker_url = broker_url
|
9
|
+
self.topics = topics
|
10
|
+
self.client = MQTTClient(client_id='')
|
11
|
+
self.client.on_message = self.on_message
|
12
|
+
self.client.on_connect = self.on_connect
|
13
|
+
self.client.on_disconnect = self.on_disconnect
|
14
|
+
|
15
|
+
async def on_startup(self, app):
|
16
|
+
self._logger.info(f"Connecting to MQTT broker at {self.broker_url}")
|
17
|
+
await self.client.connect(self.broker_url)
|
18
|
+
|
19
|
+
async def on_shutdown(self, app):
|
20
|
+
self._logger.info("Disconnecting from MQTT broker")
|
21
|
+
await self.client.disconnect()
|
22
|
+
|
23
|
+
def on_connect(self, client, flags, rc, properties):
|
24
|
+
self._logger.info("Connected to MQTT broker")
|
25
|
+
for topic in self.topics:
|
26
|
+
client.subscribe(topic)
|
27
|
+
self._logger.info(f"Subscribed to topic: {topic}")
|
28
|
+
|
29
|
+
def on_disconnect(self, client, packet, exc=None):
|
30
|
+
self._logger.warning("Disconnected from MQTT broker")
|
31
|
+
# Implement reconnection logic if needed
|
32
|
+
|
33
|
+
def on_message(self, client, topic, payload, qos, properties):
|
34
|
+
self._logger.info(f"Received message on topic {topic}: {payload}")
|
35
|
+
asyncio.create_task(self.run_actions(topic=topic, payload=payload))
|
@@ -0,0 +1,82 @@
|
|
1
|
+
from typing import Optional, Any
|
2
|
+
import aiormq
|
3
|
+
from navigator.brokers.rabbitmq import RabbitMQConnection
|
4
|
+
from .base import BaseMQTrigger
|
5
|
+
|
6
|
+
|
7
|
+
class RabbitMQTrigger(BaseMQTrigger):
|
8
|
+
def __init__(
|
9
|
+
self,
|
10
|
+
*args,
|
11
|
+
queue_name: str,
|
12
|
+
routing_key: str = '',
|
13
|
+
exchange_name: str = '',
|
14
|
+
exchange_type: str = 'topic',
|
15
|
+
credentials: Optional[str] = None,
|
16
|
+
actions: list = None,
|
17
|
+
**kwargs
|
18
|
+
):
|
19
|
+
super().__init__(
|
20
|
+
*args,
|
21
|
+
actions=actions,
|
22
|
+
queue_name=queue_name,
|
23
|
+
**kwargs
|
24
|
+
)
|
25
|
+
self._queue_name = queue_name
|
26
|
+
self._routing_key = routing_key
|
27
|
+
self._exchange_name = exchange_name
|
28
|
+
self._exchange_type = exchange_type
|
29
|
+
self._connection = RabbitMQConnection(
|
30
|
+
credentials=credentials
|
31
|
+
)
|
32
|
+
self.prefetch_count = kwargs.get('prefetch_count', 1)
|
33
|
+
|
34
|
+
async def connect(self):
|
35
|
+
await self._connection.connect()
|
36
|
+
self._logger.info("RabbitMQ connection established.")
|
37
|
+
# Ensure the exchange exists
|
38
|
+
await self._connection.ensure_exchange(
|
39
|
+
exchange_name=self._exchange_name or self._queue_name,
|
40
|
+
exchange_type=self._exchange_type
|
41
|
+
)
|
42
|
+
# Ensure the queue exists and bind it to the exchange
|
43
|
+
await self._connection.ensure_queue(
|
44
|
+
queue_name=self._queue_name,
|
45
|
+
exchange_name=self._exchange_name or self._queue_name,
|
46
|
+
routing_key=self._routing_key
|
47
|
+
)
|
48
|
+
|
49
|
+
async def disconnect(self):
|
50
|
+
await self._connection.disconnect()
|
51
|
+
self._logger.info("RabbitMQ connection closed.")
|
52
|
+
|
53
|
+
async def start_consuming(self):
|
54
|
+
await self._connection.consume_messages(
|
55
|
+
queue_name=self._queue_name,
|
56
|
+
callback=self._consumer_callback,
|
57
|
+
prefetch_count=self.prefetch_count
|
58
|
+
)
|
59
|
+
|
60
|
+
async def _consumer_callback(
|
61
|
+
self,
|
62
|
+
message: aiormq.abc.DeliveredMessage,
|
63
|
+
body: Any
|
64
|
+
) -> None:
|
65
|
+
"""
|
66
|
+
Callback from Consumer.
|
67
|
+
|
68
|
+
Used to call actions based on consumer messages received.
|
69
|
+
"""
|
70
|
+
try:
|
71
|
+
message_id = message.delivery_tag
|
72
|
+
self._logger.info(f"Received Message ID: {message_id} Body: {body}")
|
73
|
+
# Call run_actions with the received message
|
74
|
+
await self.run_actions(
|
75
|
+
message_id=message_id,
|
76
|
+
payload=message,
|
77
|
+
message=body
|
78
|
+
)
|
79
|
+
except Exception as e:
|
80
|
+
self._logger.error(f"Error in _consumer_callback: {e}")
|
81
|
+
# Handle message rejection or requeueing if necessary
|
82
|
+
await self._connection.reject_message(message, requeue=False)
|
@@ -0,0 +1,83 @@
|
|
1
|
+
from typing import Optional, Any
|
2
|
+
from navigator.brokers.redis import RedisConnection
|
3
|
+
from .base import BaseMQTrigger
|
4
|
+
|
5
|
+
|
6
|
+
class RedisTrigger(BaseMQTrigger):
|
7
|
+
"""Redis Trigger.
|
8
|
+
|
9
|
+
Trigger that listens to a Redis Stream and calls actions based on the received messages.
|
10
|
+
"""
|
11
|
+
def __init__(
|
12
|
+
self,
|
13
|
+
*args,
|
14
|
+
stream_name: str,
|
15
|
+
group_name: str = 'default_group',
|
16
|
+
consumer_name: str = 'default_consumer',
|
17
|
+
credentials: Optional[dict] = None,
|
18
|
+
actions: list = None,
|
19
|
+
**kwargs
|
20
|
+
):
|
21
|
+
super().__init__(
|
22
|
+
*args,
|
23
|
+
actions=actions,
|
24
|
+
queue_name=stream_name,
|
25
|
+
**kwargs
|
26
|
+
)
|
27
|
+
self._stream_name = stream_name
|
28
|
+
self._group_name = group_name
|
29
|
+
self._consumer_name = consumer_name
|
30
|
+
self._connection = RedisConnection(
|
31
|
+
credentials=credentials,
|
32
|
+
group_name=group_name,
|
33
|
+
consumer_name=consumer_name,
|
34
|
+
queue_name=stream_name
|
35
|
+
)
|
36
|
+
self.count = kwargs.get('count', 1)
|
37
|
+
self.block = kwargs.get('block', 1000)
|
38
|
+
|
39
|
+
async def connect(self):
|
40
|
+
await self._connection.connect()
|
41
|
+
self._logger.info(
|
42
|
+
"Redis connection established."
|
43
|
+
)
|
44
|
+
|
45
|
+
async def disconnect(self):
|
46
|
+
await self._connection.disconnect()
|
47
|
+
self._logger.info(
|
48
|
+
"Redis connection closed."
|
49
|
+
)
|
50
|
+
|
51
|
+
async def start_consuming(self):
|
52
|
+
await self._connection.consume_messages(
|
53
|
+
queue_name=self._stream_name,
|
54
|
+
callback=self._consumer_callback,
|
55
|
+
count=self.count,
|
56
|
+
block=self.block,
|
57
|
+
consumer_name=self._consumer_name
|
58
|
+
)
|
59
|
+
|
60
|
+
async def _consumer_callback(
|
61
|
+
self,
|
62
|
+
data: dict,
|
63
|
+
processed_message: Any
|
64
|
+
) -> None:
|
65
|
+
"""
|
66
|
+
Callback from Consumer.
|
67
|
+
|
68
|
+
Used to call actions based on consumer messages received.
|
69
|
+
"""
|
70
|
+
try:
|
71
|
+
message_id = data.get('message_id')
|
72
|
+
self._logger.info(
|
73
|
+
f"Received Message ID: {message_id} Body: {processed_message}"
|
74
|
+
)
|
75
|
+
# Call run_actions with the received message
|
76
|
+
await self.run_actions(
|
77
|
+
payload=data,
|
78
|
+
message_id=message_id,
|
79
|
+
message=processed_message
|
80
|
+
)
|
81
|
+
except Exception as e:
|
82
|
+
self._logger.error(f"Error in _consumer_callback: {e}")
|
83
|
+
raise
|
@@ -0,0 +1,44 @@
|
|
1
|
+
from typing import Optional, Any
|
2
|
+
from navigator.brokers.sqs import SQSConnection
|
3
|
+
from .base import BaseMQTrigger
|
4
|
+
|
5
|
+
class SQSTrigger(BaseMQTrigger):
|
6
|
+
def __init__(
|
7
|
+
self,
|
8
|
+
*args,
|
9
|
+
queue_name: str,
|
10
|
+
credentials: Optional[dict] = None,
|
11
|
+
actions: list = None,
|
12
|
+
**kwargs
|
13
|
+
):
|
14
|
+
super().__init__(
|
15
|
+
*args,
|
16
|
+
actions=actions,
|
17
|
+
queue_name=queue_name,
|
18
|
+
**kwargs
|
19
|
+
)
|
20
|
+
self._connection = SQSConnection(credentials=credentials)
|
21
|
+
self.max_messages = kwargs.get('max_messages', 10)
|
22
|
+
self.wait_time = kwargs.get('wait_time', 10)
|
23
|
+
self.idle_sleep = kwargs.get('idle_sleep', 5)
|
24
|
+
|
25
|
+
async def connect(self):
|
26
|
+
await self._connection.connect()
|
27
|
+
self._logger.info(
|
28
|
+
"AWS SQS connection established."
|
29
|
+
)
|
30
|
+
|
31
|
+
async def disconnect(self):
|
32
|
+
await self._connection.disconnect()
|
33
|
+
self._logger.info(
|
34
|
+
"AWS SQS connection closed."
|
35
|
+
)
|
36
|
+
|
37
|
+
async def start_consuming(self):
|
38
|
+
await self._connection.consume_messages(
|
39
|
+
queue_name=self._queue_name,
|
40
|
+
callback=self._consumer_callback,
|
41
|
+
max_messages=self.max_messages,
|
42
|
+
wait_time=self.wait_time,
|
43
|
+
idle_sleep=self.idle_sleep
|
44
|
+
)
|
@@ -0,0 +1,232 @@
|
|
1
|
+
import time
|
2
|
+
import os
|
3
|
+
from collections import defaultdict
|
4
|
+
from navconfig.logging import logging
|
5
|
+
from watchdog.observers import Observer
|
6
|
+
from watchdog.events import PatternMatchingEventHandler
|
7
|
+
from navigator.types import WebApp
|
8
|
+
from ...exceptions import ComponentError
|
9
|
+
from .watch import BaseWatcher, BaseWatchdog
|
10
|
+
|
11
|
+
|
12
|
+
# TODO> PatternMatchingEventHandler
|
13
|
+
|
14
|
+
fslog = logging.getLogger("watchdog.observers").setLevel(logging.WARNING)
|
15
|
+
|
16
|
+
|
17
|
+
class FsHandler(PatternMatchingEventHandler):
|
18
|
+
def __init__(self, parent: BaseWatchdog, patterns=None, *args, **kwargs):
|
19
|
+
self.not_empty = kwargs.pop("not_empty", False)
|
20
|
+
super().__init__(patterns=patterns, *args, **kwargs)
|
21
|
+
self.debounced_events = defaultdict(lambda: 0)
|
22
|
+
self.parent = parent
|
23
|
+
self.recently_created = set()
|
24
|
+
self._logger = logging.getLogger("Watcher.FS")
|
25
|
+
|
26
|
+
def zero_size(self, filepath: str):
|
27
|
+
"""Check if the file is of zero size."""
|
28
|
+
try:
|
29
|
+
return os.path.getsize(filepath) == 0
|
30
|
+
except (OSError, FileNotFoundError):
|
31
|
+
# Handle cases where the file no longer exists
|
32
|
+
return True
|
33
|
+
|
34
|
+
def process(self, event):
|
35
|
+
"""Process the event if it matches the patterns and isn't a directory."""
|
36
|
+
if event.is_directory:
|
37
|
+
return None
|
38
|
+
|
39
|
+
# Check if an event for this path has been triggered recently
|
40
|
+
last_event_time = self.debounced_events[event.src_path]
|
41
|
+
current_time = time.time()
|
42
|
+
if current_time - last_event_time < 0.5: # 0.5 seconds debounce time
|
43
|
+
return
|
44
|
+
|
45
|
+
self.debounced_events[event.src_path] = current_time
|
46
|
+
|
47
|
+
def on_created(self, event):
|
48
|
+
if event.is_directory:
|
49
|
+
return
|
50
|
+
if "created" not in self.parent.events:
|
51
|
+
return
|
52
|
+
if self.not_empty and self.zero_size(event.src_path):
|
53
|
+
self._logger.warning(
|
54
|
+
f"File {event.src_path} has zero size and 'not_empty' is True. Skipping."
|
55
|
+
)
|
56
|
+
return # Skip triggering actions
|
57
|
+
print(f"Watchdog received created event - {event.src_path} s.")
|
58
|
+
self.recently_created.add(event.src_path) # recently created
|
59
|
+
self.process(event)
|
60
|
+
# after, running actions:
|
61
|
+
args = {
|
62
|
+
"directory": self.parent.directory,
|
63
|
+
"event": event,
|
64
|
+
"on": "created",
|
65
|
+
"filename": event.src_path,
|
66
|
+
}
|
67
|
+
self.parent.call_actions(**args)
|
68
|
+
|
69
|
+
def on_modified(self, event):
|
70
|
+
"""
|
71
|
+
Handle file modification events.
|
72
|
+
|
73
|
+
This method is called when a file modification event is detected. It processes
|
74
|
+
the event and calls the appropriate actions if the event meets certain criteria.
|
75
|
+
|
76
|
+
Parameters:
|
77
|
+
event (FileSystemEvent): The event object containing information about the
|
78
|
+
file modification.
|
79
|
+
|
80
|
+
Returns:
|
81
|
+
None
|
82
|
+
|
83
|
+
Note:
|
84
|
+
- The method returns early if the event is for a directory or if 'modified'
|
85
|
+
is not in the parent's events list.
|
86
|
+
- It also returns early if the file was recently created to avoid duplicate processing.
|
87
|
+
- If the file has zero size, a warning is logged.
|
88
|
+
- The event is processed and actions are called twice with the same arguments.
|
89
|
+
"""
|
90
|
+
if event.is_directory:
|
91
|
+
return
|
92
|
+
if "modified" not in self.parent.events:
|
93
|
+
return
|
94
|
+
if event.src_path in self.recently_created:
|
95
|
+
self.recently_created.remove(event.src_path)
|
96
|
+
return
|
97
|
+
if self.not_empty and self.zero_size(event.src_path):
|
98
|
+
self._logger.warning(
|
99
|
+
f"File {event.src_path} has zero size and 'not_empty' is True. Skipping."
|
100
|
+
)
|
101
|
+
return # Skip triggering actions
|
102
|
+
print(f"Watchdog received modified event - {event.src_path} s.")
|
103
|
+
self.process(event)
|
104
|
+
args = {
|
105
|
+
"directory": self.parent.directory,
|
106
|
+
"event": event,
|
107
|
+
"on": "modified",
|
108
|
+
"filename": event.src_path,
|
109
|
+
}
|
110
|
+
self.parent.call_actions(**args)
|
111
|
+
args = {
|
112
|
+
"directory": self.parent.directory,
|
113
|
+
"event": event,
|
114
|
+
"on": "created",
|
115
|
+
"filename": event.src_path,
|
116
|
+
}
|
117
|
+
self.parent.call_actions(**args)
|
118
|
+
|
119
|
+
def on_moved(self, event):
|
120
|
+
if event.is_directory:
|
121
|
+
return
|
122
|
+
if "moved" not in self.parent.events:
|
123
|
+
return
|
124
|
+
# For moved events, check the destination path
|
125
|
+
if self.not_empty and self.zero_size(event.dest_path):
|
126
|
+
self._logger.warning(f"File {event.dest_path} has zero size and 'not_empty' is True. Skipping.")
|
127
|
+
return # Skip triggering actions
|
128
|
+
print(f"Watchdog received moved event - from {event.src_path} to {event.dest_path}.")
|
129
|
+
self.process(event)
|
130
|
+
args = {
|
131
|
+
"directory": self.parent.directory,
|
132
|
+
"event": event,
|
133
|
+
"on": "moved",
|
134
|
+
"filename": event.dest_path,
|
135
|
+
}
|
136
|
+
self.parent.call_actions(**args)
|
137
|
+
|
138
|
+
def on_deleted(self, event):
|
139
|
+
if "deleted" not in self.parent.events:
|
140
|
+
return
|
141
|
+
print(f"Watchdog received deleted event - {event.src_path} s.")
|
142
|
+
self.process(event)
|
143
|
+
args = {
|
144
|
+
"directory": self.parent.directory,
|
145
|
+
"event": event,
|
146
|
+
"on": "deleted",
|
147
|
+
"filename": event.src_path,
|
148
|
+
}
|
149
|
+
self.parent.call_actions(**args)
|
150
|
+
|
151
|
+
|
152
|
+
class FsWatcher(BaseWatcher):
|
153
|
+
def __init__(self, pattern, *args, **kwargs):
|
154
|
+
super(FsWatcher, self).__init__(*args, **kwargs)
|
155
|
+
self.directory = kwargs.pop("directory", None)
|
156
|
+
self.filename = kwargs.pop("filename", [])
|
157
|
+
self.recursive = kwargs.pop("recursive", True)
|
158
|
+
self.not_empty = kwargs.pop("not_empty", False)
|
159
|
+
self.observer = Observer()
|
160
|
+
self._patterns = pattern
|
161
|
+
|
162
|
+
def run(self):
|
163
|
+
event_handler = FsHandler(
|
164
|
+
parent=self.parent,
|
165
|
+
patterns=self._patterns,
|
166
|
+
not_empty=self.not_empty
|
167
|
+
)
|
168
|
+
self.observer.schedule(
|
169
|
+
event_handler,
|
170
|
+
self.directory,
|
171
|
+
recursive=self.recursive
|
172
|
+
)
|
173
|
+
self.observer.start()
|
174
|
+
try:
|
175
|
+
while not self.stop_event.is_set():
|
176
|
+
time.sleep(self.timeout)
|
177
|
+
except KeyboardInterrupt:
|
178
|
+
self.stop()
|
179
|
+
print("Watchdog FS Observer was stopped")
|
180
|
+
except Exception as e:
|
181
|
+
self.stop()
|
182
|
+
raise e
|
183
|
+
|
184
|
+
def stop(self):
|
185
|
+
try:
|
186
|
+
self.observer.stop()
|
187
|
+
except Exception:
|
188
|
+
pass
|
189
|
+
self.observer.join()
|
190
|
+
|
191
|
+
|
192
|
+
class FSWatchdog(BaseWatchdog):
|
193
|
+
"""FSWatchdog.
|
194
|
+
Checking for changes in the filesystem and dispatch events.
|
195
|
+
"""
|
196
|
+
|
197
|
+
timeout: int = 5
|
198
|
+
recursive: bool = True
|
199
|
+
|
200
|
+
def create_watcher(self, *args, **kwargs) -> BaseWatcher:
|
201
|
+
self.recursive = kwargs.pop("recursive", False)
|
202
|
+
self.events = kwargs.pop("on", ["created", "modified", "deleted", "moved"])
|
203
|
+
self.filename = kwargs.pop("filename", [])
|
204
|
+
self.not_empty = kwargs.pop("not_empty", False)
|
205
|
+
if not self.filename:
|
206
|
+
self.filename = ["*"]
|
207
|
+
else:
|
208
|
+
self.filename = [f"*{filename}" for filename in self.filename]
|
209
|
+
try:
|
210
|
+
self.directory = kwargs["directory"]
|
211
|
+
except KeyError as exc:
|
212
|
+
raise ComponentError("Unable to load Directory on FSWatchdog") from exc
|
213
|
+
return FsWatcher(
|
214
|
+
pattern=self.filename,
|
215
|
+
directory=self.directory,
|
216
|
+
timeout=self.timeout,
|
217
|
+
recursive=self.recursive,
|
218
|
+
not_empty=self.not_empty,
|
219
|
+
)
|
220
|
+
|
221
|
+
async def on_startup(self, app: WebApp = None) -> None:
|
222
|
+
# Perform permissions check
|
223
|
+
if not os.access(self.directory, os.R_OK | os.X_OK):
|
224
|
+
raise PermissionError(
|
225
|
+
f"Insufficient permissions to access directory '{self.directory}'. "
|
226
|
+
"Read and execute permissions are required."
|
227
|
+
)
|
228
|
+
# Start the watcher
|
229
|
+
self.watcher.start()
|
230
|
+
|
231
|
+
async def on_shutdown(self, app: WebApp = None) -> None:
|
232
|
+
self.watcher.stop()
|
@@ -0,0 +1,49 @@
|
|
1
|
+
from navigator.views import BaseHandler
|
2
|
+
from navigator.libs.json import JSONContent
|
3
|
+
from navigator.types import WebApp
|
4
|
+
from .base import BaseTrigger
|
5
|
+
|
6
|
+
|
7
|
+
class HTTPHook(BaseTrigger, BaseHandler):
|
8
|
+
"""HTTPHook.
|
9
|
+
|
10
|
+
Base Hook for all HTTP-based hooks.
|
11
|
+
|
12
|
+
"""
|
13
|
+
methods: list = ["GET", "POST"]
|
14
|
+
default_status: int = 202
|
15
|
+
|
16
|
+
def __init__(self, *args, **kwargs):
|
17
|
+
self.method: str = kwargs.pop('method', None)
|
18
|
+
if self.method:
|
19
|
+
self.methods = [self.method]
|
20
|
+
super(HTTPHook, self).__init__(*args, **kwargs)
|
21
|
+
trigger_url = kwargs.get('url', None)
|
22
|
+
if trigger_url:
|
23
|
+
self.url = trigger_url
|
24
|
+
else:
|
25
|
+
self._base_url = kwargs.get('base_url', '/api/v1/webhook/')
|
26
|
+
self.url = f"{self._base_url}{self.trigger_id}"
|
27
|
+
self._json = JSONContent()
|
28
|
+
|
29
|
+
def setup(self, app: WebApp) -> None:
|
30
|
+
super().setup(app)
|
31
|
+
self._logger.notice(
|
32
|
+
f"Set the unique URL Trigger to: {self.url}"
|
33
|
+
)
|
34
|
+
if hasattr(self, 'handle'):
|
35
|
+
self.app.router.add_route(
|
36
|
+
'POST',
|
37
|
+
self.url,
|
38
|
+
self.handle
|
39
|
+
)
|
40
|
+
else:
|
41
|
+
# Class-based Views
|
42
|
+
for method in self.methods:
|
43
|
+
handler = getattr(self, method.lower(), None)
|
44
|
+
if handler:
|
45
|
+
self.app.router.add_route(
|
46
|
+
method,
|
47
|
+
self.url,
|
48
|
+
handler
|
49
|
+
)
|