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,314 @@
|
|
1
|
+
import math
|
2
|
+
from urllib.parse import urljoin
|
3
|
+
import numpy as np
|
4
|
+
import orjson
|
5
|
+
import pandas as pd
|
6
|
+
from .flow import FlowComponent
|
7
|
+
from ..interfaces.http import HTTPService
|
8
|
+
from ..exceptions import ComponentError, DataNotFound
|
9
|
+
from ..utils.transformations import to_snake_case
|
10
|
+
|
11
|
+
|
12
|
+
class AutoTask(HTTPService, FlowComponent):
|
13
|
+
"""
|
14
|
+
AutoTask Component
|
15
|
+
|
16
|
+
Overview
|
17
|
+
|
18
|
+
This component retrieves data from AutoTask using the Autotask REST API.
|
19
|
+
It supports filtering data based on a query or specific IDs, handles pagination, and converts picklist values to human-readable labels.
|
20
|
+
|
21
|
+
.. table:: Properties
|
22
|
+
:widths: auto
|
23
|
+
|
24
|
+
+---------------------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
|
25
|
+
| Name | Required | Summary |
|
26
|
+
+---------------------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
|
27
|
+
| credentials | Yes | Dictionary containing API credentials: "API_INTEGRATION_CODE", "USERNAME", and "SECRET". Credentials can be retrieved from environment variables. |
|
28
|
+
+---------------------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
|
29
|
+
| zone | Yes | AutoTask zone (e.g., "na"). |
|
30
|
+
+---------------------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
|
31
|
+
| entity | Yes | AutoTask entity to query (e.g., "tickets"). |
|
32
|
+
+---------------------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
|
33
|
+
| query_json | No | JSON object representing the AutoTask query filter (defaults to retrieving all items). Refer to AutoTask documentation for query syntax. |
|
34
|
+
+---------------------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
|
35
|
+
| id_column_name | No | Name of the column in the output DataFrame that should represent the AutoTask record ID (defaults to "id"). |
|
36
|
+
+---------------------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
|
37
|
+
| ids | No | List of AutoTask record IDs to retrieve (overrides query_json filter if provided). |
|
38
|
+
+---------------------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
|
39
|
+
| picklist_fields | No | List of picklist fields in the entity to be converted to human-readable labels. |
|
40
|
+
+---------------------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
|
41
|
+
| user_defined_fields | No | List of user-defined fields in the entity to extract (requires "userDefinedFields" field in the response). |
|
42
|
+
+---------------------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
|
43
|
+
| fillna_values | No | Default value to replace missing data (defaults to None). |
|
44
|
+
+---------------------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
|
45
|
+
| map_field_type | No | Dictionary mapping field names to desired data types in the output DataFrame. |
|
46
|
+
+---------------------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
|
47
|
+
| force_create_columns | No | If True, ensures "IncludeFields" columns always exist, even if empty. Must be used with "IncludeFields" in "query_json". |
|
48
|
+
+---------------------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
|
49
|
+
|
50
|
+
Returns a pandas DataFrame containing the retrieved AutoTask data and additional columns for picklist labels (if applicable).
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
Example:
|
55
|
+
|
56
|
+
```yaml
|
57
|
+
AutoTask:
|
58
|
+
skipError: skip
|
59
|
+
credentials:
|
60
|
+
API_INTEGRATION_CODE: AUTOTASK_API_INTEGRATION_CODE
|
61
|
+
USERNAME: AUTOTASK_USERNAME
|
62
|
+
SECRET: AUTOTASK_SECRET
|
63
|
+
entity: TicketNotes
|
64
|
+
zone: webservices14
|
65
|
+
id_column_name: ticket_note_id
|
66
|
+
picklist_fields:
|
67
|
+
- noteType
|
68
|
+
- publish
|
69
|
+
ids: []
|
70
|
+
query_json:
|
71
|
+
IncludeFields:
|
72
|
+
- id
|
73
|
+
- createDateTime
|
74
|
+
- createdByContactID
|
75
|
+
- creatorResourceID
|
76
|
+
- description
|
77
|
+
- impersonatorCreatorResourceID
|
78
|
+
- impersonatorUpdaterResourceID
|
79
|
+
- lastActivityDate
|
80
|
+
- noteType
|
81
|
+
- publish
|
82
|
+
- ticketID
|
83
|
+
- title
|
84
|
+
Filter:
|
85
|
+
- op: gte
|
86
|
+
field: lastActivityDate
|
87
|
+
value: '{two_days_ago}'
|
88
|
+
masks:
|
89
|
+
'{two_days_ago}':
|
90
|
+
- date_diff
|
91
|
+
- value: current_date
|
92
|
+
diff: 48
|
93
|
+
mode: hours
|
94
|
+
mask: '%Y-%m-%d %H:%M:%S'
|
95
|
+
```
|
96
|
+
|
97
|
+
""" # noqa
|
98
|
+
_credentials: dict = {"API_INTEGRATION_CODE": str, "USERNAME": str, "SECRET": str}
|
99
|
+
force_create_columns: bool = False
|
100
|
+
|
101
|
+
async def start(self, **kwargs):
|
102
|
+
self.headers = None
|
103
|
+
self._proxies = None
|
104
|
+
self.auth = ""
|
105
|
+
self.auth_type = ""
|
106
|
+
self.timeout = 180
|
107
|
+
self.accept = "application/json"
|
108
|
+
self.query_json = self.mask_replacement_recursively(self.query_json)
|
109
|
+
self.processing_credentials()
|
110
|
+
|
111
|
+
self._base_url = (
|
112
|
+
f"https://{self.zone}.autotask.net/atservicesrest/v1.0/{self.entity}/"
|
113
|
+
)
|
114
|
+
|
115
|
+
self.headers = {
|
116
|
+
"Content-Type": "application/json",
|
117
|
+
"ApiIntegrationCode": self.credentials["API_INTEGRATION_CODE"],
|
118
|
+
"UserName": self.credentials["USERNAME"],
|
119
|
+
"Secret": self.credentials["SECRET"],
|
120
|
+
}
|
121
|
+
|
122
|
+
self.ids_chunks = []
|
123
|
+
if self.previous:
|
124
|
+
self.data = self.input
|
125
|
+
|
126
|
+
self.ids_chunks = self.filter_ids(
|
127
|
+
id_field=self.id_column_name,
|
128
|
+
items=self.data,
|
129
|
+
chunk_size=500,
|
130
|
+
)
|
131
|
+
elif getattr(self, "ids", None):
|
132
|
+
self._logger.info("Dropping specified Filters. Using ids instead.")
|
133
|
+
self.ids_chunks = [self.ids]
|
134
|
+
|
135
|
+
return True
|
136
|
+
|
137
|
+
async def run(self):
|
138
|
+
if not self.ids_chunks:
|
139
|
+
# Use the Filter specified in the task
|
140
|
+
df_items = await self.get_dataframe_from_entity(
|
141
|
+
payload=orjson.dumps(self.query_json),
|
142
|
+
id_column_name=self.id_column_name,
|
143
|
+
)
|
144
|
+
else:
|
145
|
+
# Use the ids from the previous component or from the ids argument
|
146
|
+
df_items = pd.DataFrame()
|
147
|
+
for ids_chunk in self.ids_chunks:
|
148
|
+
self.query_json.update(
|
149
|
+
{
|
150
|
+
"Filter": [
|
151
|
+
{"op": "in", "field": "id", "value": ids_chunk.tolist()}
|
152
|
+
]
|
153
|
+
}
|
154
|
+
)
|
155
|
+
|
156
|
+
items = await self.get_dataframe_from_entity(
|
157
|
+
payload=orjson.dumps(self.query_json),
|
158
|
+
id_column_name=self.id_column_name,
|
159
|
+
)
|
160
|
+
|
161
|
+
df_items = pd.concat([df_items, items], ignore_index=True)
|
162
|
+
|
163
|
+
if not df_items.empty and self.picklist_fields:
|
164
|
+
df_picklist_values = await self.get_picklist_values(self.picklist_fields)
|
165
|
+
|
166
|
+
if not getattr(df_picklist_values, "empty", True):
|
167
|
+
|
168
|
+
for column in [to_snake_case(field) for field in self.picklist_fields]:
|
169
|
+
df_filtered = df_picklist_values[df_picklist_values['field'] == column]
|
170
|
+
|
171
|
+
# Merge the label into df_items
|
172
|
+
df_items = df_items.merge(
|
173
|
+
df_filtered[['label', 'value']],
|
174
|
+
how='left',
|
175
|
+
left_on=column,
|
176
|
+
right_on='value'
|
177
|
+
)
|
178
|
+
|
179
|
+
# Rename the label column to reflect the original field
|
180
|
+
df_items.rename(columns={'label': f'{column}_label'}, inplace=True)
|
181
|
+
|
182
|
+
# Drop the 'value' column from the merge
|
183
|
+
df_items.drop(columns=['value'], inplace=True)
|
184
|
+
|
185
|
+
if "IncludeFields" in self.query_json and self.force_create_columns:
|
186
|
+
required_columns = self._get_force_create_columns()
|
187
|
+
|
188
|
+
if df_items.empty:
|
189
|
+
# Create a DataFrame with one row filled with NaNs based on IncludeFields
|
190
|
+
empty_dataset = {field: [pd.NA] for field in required_columns}
|
191
|
+
df_items = pd.DataFrame(empty_dataset)
|
192
|
+
else:
|
193
|
+
df_items = df_items.reindex(columns=required_columns, fill_value=pd.NA)
|
194
|
+
|
195
|
+
self._result = df_items
|
196
|
+
# Add Debugging Block
|
197
|
+
if self._debug is True:
|
198
|
+
print("::: Printing Result Data === ")
|
199
|
+
print("Data: ", self._result)
|
200
|
+
for column, t in df_items.dtypes.items():
|
201
|
+
print(column, "->", t, "->", df_items[column].iloc[0])
|
202
|
+
return self._result
|
203
|
+
|
204
|
+
async def close(self):
|
205
|
+
pass
|
206
|
+
|
207
|
+
def _get_force_create_columns(self):
|
208
|
+
required_columns = list(map(to_snake_case, self.query_json["IncludeFields"]))
|
209
|
+
|
210
|
+
try:
|
211
|
+
idx = required_columns.index("id")
|
212
|
+
required_columns[idx] = self.id_column_name
|
213
|
+
|
214
|
+
return required_columns
|
215
|
+
|
216
|
+
except ValueError:
|
217
|
+
self.logger.error("The item 'id' was not found in the list.")
|
218
|
+
|
219
|
+
def filter_ids(self, id_field: str, items: pd.DataFrame, chunk_size):
|
220
|
+
data = items[id_field].dropna().unique().astype(int)
|
221
|
+
|
222
|
+
if data.size > 0:
|
223
|
+
split_n = math.ceil(data.size / chunk_size)
|
224
|
+
|
225
|
+
# Split into chunks of n items
|
226
|
+
return np.array_split(data, split_n) # Convert to NumPy array and split
|
227
|
+
|
228
|
+
return [data]
|
229
|
+
|
230
|
+
def get_autotask_url(self, resource):
|
231
|
+
return urljoin(self._base_url, resource)
|
232
|
+
|
233
|
+
async def get_dataframe_from_entity(self, payload, id_column_name):
|
234
|
+
args = {
|
235
|
+
"url": self.get_autotask_url("query"),
|
236
|
+
"method": "post",
|
237
|
+
"data": payload,
|
238
|
+
}
|
239
|
+
|
240
|
+
results = []
|
241
|
+
while True:
|
242
|
+
result, error = await self.session(**args)
|
243
|
+
|
244
|
+
if error:
|
245
|
+
self._logger.error(f"{__name__}: Error getting {self.entity}")
|
246
|
+
raise ComponentError(f"{__name__}: Error getting {self.entity}") from error
|
247
|
+
|
248
|
+
if result is None:
|
249
|
+
self._logger.error(f"API returned None or empty result for {args['url']}")
|
250
|
+
raise ComponentError(f"API returned None or empty result for {args['url']}")
|
251
|
+
|
252
|
+
if "items" not in result:
|
253
|
+
self._logger.error(f"'items' not found in API response: {result}")
|
254
|
+
raise ComponentError("'items' not found in API response")
|
255
|
+
|
256
|
+
results.extend(result.get("items", []))
|
257
|
+
|
258
|
+
args.update({"url": result["pageDetails"].get("nextPageUrl", None)})
|
259
|
+
|
260
|
+
if not args["url"]:
|
261
|
+
break
|
262
|
+
try:
|
263
|
+
df_results = await self.create_dataframe(results)
|
264
|
+
except DataNotFound as e:
|
265
|
+
if self.force_create_columns:
|
266
|
+
return pd.DataFrame()
|
267
|
+
|
268
|
+
raise e
|
269
|
+
|
270
|
+
if not df_results.empty and "userDefinedFields" in df_results.columns:
|
271
|
+
df_results_udf = df_results["userDefinedFields"].apply(self.extract_udf)
|
272
|
+
df_results = df_results.drop("userDefinedFields", axis=1, errors="ignore").join(df_results_udf)
|
273
|
+
|
274
|
+
df_results = (
|
275
|
+
df_results.rename(columns=lambda x: to_snake_case(x))
|
276
|
+
.rename(columns={"id": id_column_name})
|
277
|
+
)
|
278
|
+
|
279
|
+
return df_results
|
280
|
+
|
281
|
+
@staticmethod
|
282
|
+
def extract_udf(row):
|
283
|
+
""" Extracts dictionary values into columns"""
|
284
|
+
return pd.Series({d['name']: d['value'] for d in row})
|
285
|
+
|
286
|
+
async def get_picklist_values(self, field_names: list[str]) -> pd.DataFrame:
|
287
|
+
result, error = await self.session(
|
288
|
+
url=self.get_autotask_url("entityInformation/fields"),
|
289
|
+
method="get",
|
290
|
+
)
|
291
|
+
|
292
|
+
if error:
|
293
|
+
self._logger.error(f"{__name__}: Error getting {self.entity}")
|
294
|
+
raise ComponentError(f"{__name__}: Error getting {self.entity}") from error
|
295
|
+
|
296
|
+
picklist_data = []
|
297
|
+
|
298
|
+
for field_name in field_names:
|
299
|
+
for field in result["fields"]:
|
300
|
+
if field["name"] == field_name:
|
301
|
+
self._logger.info(f"Extracting picking list values for {field_name}")
|
302
|
+
|
303
|
+
if not field["picklistValues"]:
|
304
|
+
df = pd.DataFrame(columns=["label", "value"])
|
305
|
+
else:
|
306
|
+
df = await self.create_dataframe(field["picklistValues"])
|
307
|
+
df = df[["label", "value"]]
|
308
|
+
|
309
|
+
df["field"] = to_snake_case(field_name)
|
310
|
+
picklist_data.append(df)
|
311
|
+
|
312
|
+
# Concatenate all DataFrames and reset the index
|
313
|
+
combined_df = pd.concat(picklist_data).reset_index(drop=True).astype({"value": "int"})
|
314
|
+
return combined_df[["field", "label", "value"]]
|
@@ -0,0 +1,80 @@
|
|
1
|
+
import asyncio
|
2
|
+
from collections.abc import Callable
|
3
|
+
from ..interfaces.AzureClient import AzureClient
|
4
|
+
from ..interfaces.http import HTTPService
|
5
|
+
from .flow import FlowComponent
|
6
|
+
|
7
|
+
|
8
|
+
class Azure(AzureClient, HTTPService, FlowComponent):
|
9
|
+
"""
|
10
|
+
Azure Component.
|
11
|
+
|
12
|
+
Overview
|
13
|
+
|
14
|
+
This component interacts with Azure services using the Azure SDK for Python.
|
15
|
+
It requires valid Azure credentials to establish a connection.
|
16
|
+
|
17
|
+
.. table:: Properties
|
18
|
+
:widths: auto
|
19
|
+
|
20
|
+
+--------------------------+----------+-----------+----------------------------------------------------------------+
|
21
|
+
| Name | Required | Summary |
|
22
|
+
+--------------------------+----------+-----------+----------------------------------------------------------------+
|
23
|
+
| credentials (optional) | Yes | Dictionary containing Azure credentials: "client_id", "tenant_id", |
|
24
|
+
| | | and "client_secret". Credentials can be retrieved from environment |
|
25
|
+
| | | variables. |
|
26
|
+
+--------------------------+----------+-----------+----------------------------------------------------------------+
|
27
|
+
| as_dataframe (optional) | No | Specifies if the response should be converted to a pandas DataFrame |
|
28
|
+
| | | (default: False). |
|
29
|
+
+--------------------------+----------+-----------+----------------------------------------------------------------+
|
30
|
+
|
31
|
+
This component does not return any data directly. It interacts with
|
32
|
+
Azure services based on the configuration and potentially triggers
|
33
|
+
downstream components in a task.
|
34
|
+
""" # noqa: E501
|
35
|
+
accept: str = "application/json"
|
36
|
+
no_host: bool = True
|
37
|
+
|
38
|
+
def __init__(
|
39
|
+
self,
|
40
|
+
loop: asyncio.AbstractEventLoop = None,
|
41
|
+
job: Callable = None,
|
42
|
+
stat: Callable = None,
|
43
|
+
**kwargs,
|
44
|
+
):
|
45
|
+
self.as_dataframe: bool = kwargs.get("as_dataframe", False)
|
46
|
+
# Initialize parent classes explicitly
|
47
|
+
super().__init__(loop=loop, job=job, stat=stat, **kwargs)
|
48
|
+
if 'secret_id' in self.credentials:
|
49
|
+
self.credentials['client_secret'] = self.credentials.pop('secret_id')
|
50
|
+
|
51
|
+
async def close(self, timeout: int = 5):
|
52
|
+
"""close.
|
53
|
+
Closing the connection.
|
54
|
+
"""
|
55
|
+
pass
|
56
|
+
|
57
|
+
async def open(self, host: str, port: int, credentials: dict, **kwargs):
|
58
|
+
"""open.
|
59
|
+
Starts (open) a connection to external resource.
|
60
|
+
"""
|
61
|
+
self.app = self.get_msal_app()
|
62
|
+
return self
|
63
|
+
|
64
|
+
async def start(self, **kwargs):
|
65
|
+
"""Start.
|
66
|
+
|
67
|
+
Processing variables and credentials.
|
68
|
+
"""
|
69
|
+
await super(Azure, self).start(**kwargs)
|
70
|
+
self.processing_credentials()
|
71
|
+
try:
|
72
|
+
self.client_id, self.tenant_id, self.client_secret = (
|
73
|
+
self.credentials.get(key)
|
74
|
+
for key in ["client_id", "tenant_id", "client_secret"]
|
75
|
+
)
|
76
|
+
except Exception as err:
|
77
|
+
self._logger.error(err)
|
78
|
+
raise
|
79
|
+
|
80
|
+
return True
|
@@ -0,0 +1,106 @@
|
|
1
|
+
import iso8601
|
2
|
+
from datetime import datetime, time, timezone
|
3
|
+
from .Azure import Azure
|
4
|
+
from ..exceptions import ComponentError, DataNotFound
|
5
|
+
|
6
|
+
class AzureUsers(Azure):
|
7
|
+
"""
|
8
|
+
|
9
|
+
AzureUsers Component
|
10
|
+
|
11
|
+
Overview
|
12
|
+
|
13
|
+
This component retrieves a list of users from Azure Active Directory (AAD) using the Microsoft Graph API.
|
14
|
+
|
15
|
+
.. table:: Properties
|
16
|
+
:widths: auto
|
17
|
+
|
18
|
+
+------------------------+----------+-----------+---------------------------------------------------------------------------------+
|
19
|
+
| Name | Required | Summary |
|
20
|
+
+------------------------+----------+-----------+---------------------------------------------------------------------------------+
|
21
|
+
| credentials | Yes | Dictionary placeholder for Azure AD application credentials. |
|
22
|
+
+------------------------+----------+-----------+---------------------------------------------------------------------------------+
|
23
|
+
| most_recent (optional) | No | ISO 8601-formatted date and time string to filter users created on or after that date/time. | |
|
24
|
+
+------------------------+----------+-----------+---------------------------------------------------------------------------------+
|
25
|
+
|
26
|
+
**Returns**
|
27
|
+
|
28
|
+
A pandas DataFrame containing the retrieved user information. Each row represents an Azure user, and columns might include properties like:
|
29
|
+
|
30
|
+
- `objectId`: Unique identifier for the user in AAD.
|
31
|
+
- `displayName`: User's display name.
|
32
|
+
- `userPrincipalName`: User's email address (usually the primary login).
|
33
|
+
- ... (other user properties depending on the AAD response)
|
34
|
+
|
35
|
+
**Error Handling**
|
36
|
+
|
37
|
+
- The component raises a `ComponentError` with a detailed message in case of errors during authentication, API calls, or data processing. This error will be surfaced within your Flowtask workflow.
|
38
|
+
|
39
|
+
|
40
|
+
Example:
|
41
|
+
|
42
|
+
```yaml
|
43
|
+
AzureUsers:
|
44
|
+
recent: '2023-10-01'
|
45
|
+
```
|
46
|
+
|
47
|
+
""" # noqa: E501
|
48
|
+
accept: str = 'application/json'
|
49
|
+
|
50
|
+
async def get_users(self, most_recent: str = None):
|
51
|
+
async def fetch_users(url: str, all_users: list):
|
52
|
+
result, error = await self.async_request(url, self.method)
|
53
|
+
if error:
|
54
|
+
raise ComponentError(
|
55
|
+
f"{__name__}: Error in AzureUsers: {error}"
|
56
|
+
)
|
57
|
+
|
58
|
+
all_users.extend(result.get("value", []))
|
59
|
+
|
60
|
+
next_link = result.get("@odata.nextLink")
|
61
|
+
if next_link:
|
62
|
+
await fetch_users(next_link, all_users)
|
63
|
+
|
64
|
+
all_users = []
|
65
|
+
if most_recent:
|
66
|
+
utc_datetime = (
|
67
|
+
iso8601.parse_date(most_recent).isoformat().replace("+00:00", "Z")
|
68
|
+
)
|
69
|
+
url = f"{self.users_info}?$filter=createdDateTime ge {utc_datetime}"
|
70
|
+
else:
|
71
|
+
url = f"{self.users_info}"
|
72
|
+
await fetch_users(url, all_users)
|
73
|
+
return all_users
|
74
|
+
|
75
|
+
async def run(self):
|
76
|
+
"""Run Azure Connection for getting Users Info."""
|
77
|
+
self._logger.info(
|
78
|
+
f"<{__name__}>: Starting Azure Connection for getting Users Info."
|
79
|
+
)
|
80
|
+
self.app = self.get_msal_app()
|
81
|
+
token, self.token_type = self.get_token()
|
82
|
+
self.auth["apikey"] = token
|
83
|
+
self.headers["Content-Type"] = "application/json"
|
84
|
+
self.method = "GET"
|
85
|
+
try:
|
86
|
+
more_recent = None
|
87
|
+
if hasattr(self, "recent"):
|
88
|
+
more_recent = self.mask_replacement(self.recent)
|
89
|
+
result = await self.get_users(more_recent)
|
90
|
+
self._logger.info(f"<{__name__}>: Successfully got Users Info.")
|
91
|
+
self._result = await self.create_dataframe(result)
|
92
|
+
if self._result is None:
|
93
|
+
raise DataNotFound(
|
94
|
+
"No data found for Azure Users."
|
95
|
+
)
|
96
|
+
except Exception as err:
|
97
|
+
self._logger.error(err)
|
98
|
+
raise ComponentError(f"{__name__}: Error in AzureUsers: {err}") from err
|
99
|
+
numrows = len(self._result.index)
|
100
|
+
self.add_metric("NUM_USERS", numrows)
|
101
|
+
if self._debug is True:
|
102
|
+
print(self._result)
|
103
|
+
print("::: Printing Column Information === ")
|
104
|
+
for column, t in self._result.dtypes.items():
|
105
|
+
print(column, "->", t, "->", self._result[column].iloc[0])
|
106
|
+
return self._result
|
@@ -0,0 +1,91 @@
|
|
1
|
+
import asyncio
|
2
|
+
from abc import ABC
|
3
|
+
from typing import List, Dict, Union
|
4
|
+
from collections.abc import Callable
|
5
|
+
from ..exceptions import DataNotFound, ComponentError
|
6
|
+
from .flow import FlowComponent
|
7
|
+
|
8
|
+
|
9
|
+
class BaseAction(FlowComponent, ABC):
|
10
|
+
"""
|
11
|
+
BaseAction Component
|
12
|
+
|
13
|
+
Overview
|
14
|
+
Basic component for making RESTful queries to URLs.
|
15
|
+
This component serves as a foundation for building more specific action components.
|
16
|
+
It allows you to define methods (functions) that can be executed asynchronously.
|
17
|
+
|
18
|
+
.. table:: Properties
|
19
|
+
:widths: auto
|
20
|
+
|
21
|
+
+-----------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------+
|
22
|
+
| Name | Required | Summary |
|
23
|
+
+-----------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------+
|
24
|
+
| loop (optional) | No | Event loop to use for asynchronous operations (defaults to the current event loop). |
|
25
|
+
+-----------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------+
|
26
|
+
| job (optional) | No | Reference to a job object for logging and tracking purposes. |
|
27
|
+
+-----------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------+
|
28
|
+
| stat (optional) | No | Reference to a stat object for custom metrics collection. |
|
29
|
+
+-----------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------+
|
30
|
+
| method (from kwargs) | Yes | Name of the method (function) within the component to be executed. Specified as a keyword argument during initialization. |
|
31
|
+
+-----------------------+----------+-----------+---------------------------------------------------------------------------------------------------------------+
|
32
|
+
|
33
|
+
**Returns**
|
34
|
+
|
35
|
+
The output data can vary depending on the implemented method. It can be a list, dictionary, or any data structure returned by the executed method.
|
36
|
+
|
37
|
+
**Error Handling**
|
38
|
+
|
39
|
+
- `DataNotFound`: This exception is raised if the executed method doesn't return any data.
|
40
|
+
- `ComponentError`: This exception is raised for any other errors encountered during execution.
|
41
|
+
|
42
|
+
|
43
|
+
"""
|
44
|
+
|
45
|
+
def __init__(
|
46
|
+
self,
|
47
|
+
loop: asyncio.AbstractEventLoop = None,
|
48
|
+
job: Callable = None,
|
49
|
+
stat: Callable = None,
|
50
|
+
**kwargs,
|
51
|
+
) -> None:
|
52
|
+
"""Init Method."""
|
53
|
+
self._result: Union[List, Dict] = None
|
54
|
+
self._method: str = kwargs.pop("method", None)
|
55
|
+
super().__init__(loop=loop, job=job, stat=stat, **kwargs)
|
56
|
+
args = self._attrs.get("args", {})
|
57
|
+
keys_to_remove = ["loop", "stat", "debug", "memory", "comment", "Group"]
|
58
|
+
self._kwargs = {k: v for k, v in args.items() if k not in keys_to_remove}
|
59
|
+
|
60
|
+
async def start(self, **kwargs):
|
61
|
+
if not hasattr(self, self._method):
|
62
|
+
raise ComponentError(f"{self.__name__} Error: has no Method {self._method}")
|
63
|
+
# Getting the method to be called
|
64
|
+
self._fn = getattr(self, self._method)
|
65
|
+
await super(BaseAction, self).start(**kwargs)
|
66
|
+
# Processing Variables:
|
67
|
+
self._kwargs = self.var_replacement(self._kwargs)
|
68
|
+
return True
|
69
|
+
|
70
|
+
async def close(self):
|
71
|
+
pass
|
72
|
+
|
73
|
+
async def run(self):
|
74
|
+
try:
|
75
|
+
result, error = await self._fn(**self._kwargs)
|
76
|
+
if error:
|
77
|
+
self._logger.warning(
|
78
|
+
f"Error {self.__name__}.{self._fn.__name__}: {error}"
|
79
|
+
)
|
80
|
+
return False
|
81
|
+
if result is None:
|
82
|
+
raise DataNotFound(
|
83
|
+
f"No data found for {self.__name__}.{self._fn.__name__}"
|
84
|
+
)
|
85
|
+
self._result = result
|
86
|
+
self.add_metric(f"{self.__name__}.{self._fn.__name__}", result)
|
87
|
+
except DataNotFound:
|
88
|
+
raise
|
89
|
+
except Exception as e:
|
90
|
+
raise ComponentError(f"Error running {self.__name__}: {e}")
|
91
|
+
return self._result
|