├── images ├── secret.png └── architecture.jpg ├── functions ├── erp-file-load │ ├── func.yaml │ ├── requirements.txt │ ├── test_scripts │ │ └── triggerdummyevent.sh │ ├── sample_files │ │ └── sampleevent.json │ └── func.py ├── erp-callback │ ├── requirements.txt │ ├── func.yaml │ ├── test_scripts │ │ └── testdummycallback.sh │ ├── samplePayloads │ │ ├── jsoncallback.json │ │ └── sampleCallback.xml │ └── func.py └── erp-transform-file │ ├── requirements.txt │ ├── APInvoiceLinesTemplate.csv.template │ ├── func.yaml │ ├── test_scripts │ ├── triggerdummyevent.sh │ └── loadtestfile2oci.sh │ ├── APInvoiceTemplate.csv.template │ ├── sample_files │ ├── sampleEvent.json │ └── createInvoiceSample.json │ ├── erp_data_file.py │ └── func.py ├── .gitignore ├── terraform ├── versions.tf ├── general_config.auto.tfvars.template ├── oci_config.auto.tfvars.template ├── appconfig.tmpl ├── terraform.tfvars.template ├── apigw.tf ├── topic.tf ├── functionsmodule │ └── functions.tf ├── functionsapp.tf ├── storage.tf ├── vault.tf ├── network.tf ├── events.tf └── variables.tf ├── SECURITY.md ├── LICENSE.txt ├── CONTRIBUTING.md ├── README.md └── THIRD_PARTY_LICENSE.txt /images/secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/sample-serverless-saas-erp-dataload/HEAD/images/secret.png -------------------------------------------------------------------------------- /images/architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/sample-serverless-saas-erp-dataload/HEAD/images/architecture.jpg -------------------------------------------------------------------------------- /functions/erp-file-load/func.yaml: -------------------------------------------------------------------------------- 1 | schema_version: 20180708 2 | name: erp-file-load 3 | version: 0.0.104 4 | runtime: python 5 | entrypoint: /python/bin/fdk /function/func.py handler 6 | memory: 512 7 | -------------------------------------------------------------------------------- /functions/erp-callback/requirements.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | 5 | 6 | fdk==0.1.21 7 | oci==2.24.0 -------------------------------------------------------------------------------- /functions/erp-transform-file/requirements.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | 5 | 6 | fdk==0.1.21 7 | oci==2.24.0 -------------------------------------------------------------------------------- /functions/erp-file-load/requirements.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | 5 | fdk==0.1.21 6 | oci==2.24.0 7 | requests==2.24.0 8 | -------------------------------------------------------------------------------- /functions/erp-transform-file/APInvoiceLinesTemplate.csv.template: -------------------------------------------------------------------------------- 1 | $INVOICEID,$INVOICELINENUM,ITEM,$AMOUNT,,,,$DESCRIPTION,,,,,,,,,,,,,N,,#NULL,$ACCOUNTINGDATE,,,,,#NULL,,,,,,,,,,,,,,,,,#NULL,,,N,1,,,N,,,,,,,N,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,END 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.fpr 2 | tools/ 3 | Fortifyserverless* 4 | __pycache__ 5 | .scannerwork/ 6 | .idea 7 | runsonar.sh 8 | setconfig.sh 9 | .terraform 10 | *.tfstate 11 | .terraform 12 | *.auto.tfvars 13 | terraform.tfvars 14 | runsonar_nopublish.sh 15 | terraform.tfstate 16 | *.backup 17 | .idea 18 | *.tfvars 19 | -------------------------------------------------------------------------------- /functions/erp-file-load/test_scripts/triggerdummyevent.sh: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | set -x 4 | cat ../sample_files/sampleevent.json | fn invoke Serverless_Integration erp-file-load 5 | -------------------------------------------------------------------------------- /terraform/versions.tf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | terraform { 5 | required_providers { 6 | oci = { 7 | source = "hashicorp/oci" 8 | } 9 | } 10 | required_version = ">= 0.13" 11 | } 12 | -------------------------------------------------------------------------------- /functions/erp-callback/func.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | 5 | schema_version: 20180708 6 | name: erp-callback 7 | version: 0.0.43 8 | runtime: python 9 | entrypoint: /python/bin/fdk /function/func.py handler 10 | memory: 512 11 | -------------------------------------------------------------------------------- /functions/erp-transform-file/func.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | 5 | schema_version: 20180708 6 | name: erp-transform-file 7 | version: 0.0.43 8 | runtime: python 9 | entrypoint: /python/bin/fdk /function/func.py handler 10 | memory: 512 11 | -------------------------------------------------------------------------------- /functions/erp-transform-file/test_scripts/triggerdummyevent.sh: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | # triggers a dummy event , 4 | # 5 | set -x 6 | # ./loadtestfile2oci.sh 7 | cat ../sample_files/sampleEvent.json | fn invoke Serverless_Integration erp-transform-file 8 | -------------------------------------------------------------------------------- /functions/erp-callback/test_scripts/testdummycallback.sh: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | # This script calls the callback function with a dummy event. Change the app name to suit your configuration 4 | set -x 5 | cat ../samplePayloads/sampleCallback.xml | fn invoke Serverless_Integration erp-callback 6 | 7 | -------------------------------------------------------------------------------- /functions/erp-transform-file/APInvoiceTemplate.csv.template: -------------------------------------------------------------------------------- 1 | $INVOICEID,$BUSINESSUNIT,$SOURCE,$INVOICENUMBER,$INVOICEAMOUNT,$INVOICEDATE,$SUPPLIERNAME,$SUPPLIERNUMBER,$SUPPLIERSITE,$INVOICECURRENCY,$PAYMENTCURRENCY,$DESCRIPTION,AP_Cloud_Demo,STANDARD,,,,,,$PAYMENTTERMS,$TERMSDATE,,,$ACCOUNTINGDATE,CHECK,Standard,#NULL,,,,,,,,,,,#NULL,,,,,#NULL,#NULL,,,,21,#NULL,,,#NULL,#NULL,,,,#NULL,,,,,,,,,,,,,,,N,N,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,END 2 | -------------------------------------------------------------------------------- /terraform/general_config.auto.tfvars.template: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | fusion_server = { 5 | erp_hostname = "xxxxx.oraclecloud.com" 6 | erp_username = "xxxx.yyyy" 7 | } 8 | oci-namespace="xxxxx" 9 | notification_email="xxxx.yyyy@youcompany.com" 10 | compartment_ocid="ocid1.compartment.oc1..xxxx11112223334445556667778" -------------------------------------------------------------------------------- /functions/erp-transform-file/test_scripts/loadtestfile2oci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2021, Oracle and/or its affiliates. 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 4 | 5 | if [ -z "$1" ] 6 | then 7 | echo "usage : test_loadfile2oci.sh " 8 | exit -1 9 | fi 10 | 11 | 12 | # Upload file 13 | oci os object put -ns $1 -bn Serverless_Integration_json_inbound --file ../sample_files/createInvoiceSample.json --name createInvoiceSample.`uuidgen | cut -c1-8`.json --force 14 | 15 | -------------------------------------------------------------------------------- /terraform/oci_config.auto.tfvars.template: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | # First few lines are copy of oci cli config 5 | # This file should not be put onto version control 6 | # This file is the same format as your OCI config file, 7 | # 8 | user="ocid1.user.oc1..11111222233334444" 9 | fingerprint="11:22:33:44:55:66:77:88:99:00" 10 | key_file="/home/xxxxx/.oci/oci_api_key.pem" 11 | tenancy="ocid1.tenancy.oc1..112233445566787990" 12 | region="xx-yyyyyy-z" -------------------------------------------------------------------------------- /terraform/appconfig.tmpl: -------------------------------------------------------------------------------- 1 | { 2 | "json_inbound_bucket_name" : "${datafile_buckets.json_inbound_bucket_name}", 3 | "zip_inbound_bucket_name" : "${datafile_buckets.zip_inbound_bucket_name}", 4 | "processing_bucket_name" : "${datafile_buckets.processing_bucket_name}", 5 | "succeeded_bucket_name" : "${datafile_buckets.succeeded_bucket_name}", 6 | "failed_bucket_name" : "${datafile_buckets.failed_bucket_name}", 7 | "ons_error_topic_ocid" : "${ons_error_topic_ocid}", 8 | "ons_info_topic_ocid" : "${ons_info_topic_ocid}", 9 | "erp_url" : "https://${fusion_server.erp_hostname}/fscmRestApi/resources/latest/erpintegrations", 10 | "erp_username" : "${fusion_server.erp_username}", 11 | "erp_password_vault_ocid" : "${erp_password_vault_ocid}", 12 | "erp_jobname" : "${fusion_properties.erp_jobname}", 13 | "erp_paramlist" : "${fusion_properties.erp_paramlist}", 14 | "erp_callback_url" : "https://${apigw.hostname}${fnapp.pathprefix}${fn["erp-callback"].path}" 15 | } 16 | -------------------------------------------------------------------------------- /functions/erp-file-load/sample_files/sampleevent.json: -------------------------------------------------------------------------------- 1 | { 2 | "eventType": "com.oraclecloud.objectstorage.createobject", 3 | "cloudEventsVersion": "0.1", 4 | "eventTypeVersion": "2.0", 5 | "source": "ObjectStorage", 6 | "eventTime": "2020-09-21T15:58:34Z", 7 | "contentType": "application/json", 8 | "data": { 9 | "compartmentId": "ocid1.compartment.oc1..xxxxx", 10 | "compartmentName": "xxxx-xxxxx", 11 | "resourceName": "createInvoiceSample.zip", 12 | "resourceId": "/n/ateamsaas/b/Serverless_Integration_zip_inbound/o/createInvoiceSample.zip", 13 | "availabilityDomain": "PHX-AD-1", 14 | "additionalDetails": { 15 | "bucketName": "Serverless_Integration_zip_inbound", 16 | "versionId": "xxxx", 17 | "archivalState": "Available", 18 | "namespace": "xxxx", 19 | "bucketId": "ocid1.bucket.oc1.phx.xxxxx", 20 | "eTag": "xxxx" 21 | } 22 | }, 23 | "eventID": "xxxx", 24 | "extensions": { 25 | "compartmentId": "ocid1.compartment.oc1..xxxxx" 26 | } 27 | } -------------------------------------------------------------------------------- /terraform/terraform.tfvars.template: -------------------------------------------------------------------------------- 1 | functionsapp = { 2 | subnet = ">" 3 | appname = "Serverless_Integration" 4 | pathprefix = "/serverless_integration" 5 | 6 | syslogurl = null 7 | 8 | # fn context file can be found in $HOME/.fn/contexts/something.yaml 9 | contextfile = "" 10 | config_template = "appconfig.tmpl" 11 | } 12 | 13 | functions = [ 14 | { 15 | fnpath = "../functions/erp-transform-file" 16 | path = null 17 | methods = [] 18 | yamlfile = "func.yaml" 19 | timeout = 150 20 | }, 21 | { 22 | fnpath = "../functions/erp-file-load" 23 | path =null 24 | methods = [] 25 | yamlfile = "func.yaml" 26 | timeout = 150 27 | }, 28 | { 29 | fnpath = "../functions/erp-callback" 30 | path = "/erp-callback" 31 | methods = ["GET"] 32 | yamlfile = "func.yaml" 33 | timeout = 150 34 | }, 35 | ] 36 | 37 | 38 | -------------------------------------------------------------------------------- /functions/erp-transform-file/sample_files/sampleEvent.json: -------------------------------------------------------------------------------- 1 | { 2 | "eventType": "com.oraclecloud.objectstorage.createobject", 3 | "cloudEventsVersion": "0.1", 4 | "eventTypeVersion": "2.0", 5 | "source": "ObjectStorage", 6 | "eventTime": "2020-09-21T15:58:34Z", 7 | "contentType": "application/json", 8 | "data": { 9 | "compartmentId": "ocid1.compartment.oc1..xxxx", 10 | "compartmentName": "xxxx-compartment_20191015152819", 11 | "resourceName": "createInvoiceSample.json", 12 | "resourceId": "/n/ateamsaas/b/Serverless_Integration_json_inbound/o/createInvoiceSample.json", 13 | "availabilityDomain": "PHX-AD-1", 14 | "additionalDetails": { 15 | "bucketName": "Serverless_Integration_json_inbound", 16 | "versionId": "xxxxx-b94c-47ab-8f78-xxx", 17 | "archivalState": "Available", 18 | "namespace": "ateamsaas", 19 | "bucketId": "ocid1.bucket.oc1.phx.xxxx", 20 | "eTag": "xx-1335-45f7-b0f3-xxx" 21 | } 22 | }, 23 | "eventID": "xxx-b52f-6999-8ee3-xx", 24 | "extensions": { 25 | "compartmentId": "ocid1.compartment.oc1..xxxx" 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /functions/erp-transform-file/sample_files/createInvoiceSample.json: -------------------------------------------------------------------------------- 1 | { 2 | "invoices": [ 3 | { 4 | "invoiceId": "222290", 5 | "businessUnit": "US1 Business Unit", 6 | "source": "External", 7 | "invoiceNumber": "111190", 8 | "invoiceAmount": "4242.00", 9 | "invoiceDate" : "2019/02/01", 10 | "supplierName": "Staffing Services", 11 | "supplierNumber" : 1253, 12 | "supplierSite" : "Staffing US1", 13 | "invoiceCurrency": "USD", 14 | "paymentCurrency": "USD", 15 | "description" : "New Invoice from global Angels", 16 | "importSet": "AP_Cloud_Demo", 17 | "invoiceType": "STANDARD", 18 | "paymentTerms": "Immediate", 19 | "termsDate": "2019/02/01", 20 | "accountingDate": "2019/02/01", 21 | "paymentMethod": "CHECK", 22 | "invoiceLines": [ 23 | { 24 | "amount": "200", 25 | "description" : "Invoice Line Description" 26 | }, 27 | { 28 | "amount": "300", 29 | "description" : "Invoice Line Description2", 30 | "invoiceQuantity": "10", 31 | "unitPrice": "5" 32 | 33 | } 34 | ] 35 | } 36 | 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /terraform/apigw.tf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | resource "oci_apigateway_gateway" "ServerlessIntegration_gateway" { 5 | compartment_id = var.compartment_ocid 6 | endpoint_type = "PUBLIC" 7 | display_name = "ServerlessIntegration_APIGW" 8 | subnet_id = oci_core_subnet.ServerlessIntegration_subnet.id 9 | } 10 | 11 | resource "oci_apigateway_deployment" "ServerlessIntegration_Deployment" { 12 | compartment_id = var.compartment_ocid 13 | display_name = "ServerlessIntegration_Deployment" 14 | gateway_id = oci_apigateway_gateway.ServerlessIntegration_gateway.id 15 | path_prefix = var.functionsapp.pathprefix 16 | specification { 17 | request_policies { 18 | } 19 | dynamic "routes" { 20 | for_each = {for func in local.functions: basename(func.fnpath)=>func if length(func.methods)>0 && func.path!=null} 21 | content { 22 | backend { 23 | type = "ORACLE_FUNCTIONS_BACKEND" 24 | function_id = module.functions[routes.key].function_ocid 25 | } 26 | path = routes.value.path 27 | methods = routes.value.methods 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /terraform/topic.tf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | resource "oci_ons_notification_topic" "ServerlessIntegration_ERROR_TOPIC" { 5 | compartment_id = var.compartment_ocid 6 | name = "ServerlessIntegration_ERROR_TOPIC" 7 | description = "All error messages from the ERP integration flow end up being posted here" 8 | } 9 | resource "oci_ons_notification_topic" "ServerlessIntegration_INFO_TOPIC" { 10 | compartment_id = var.compartment_ocid 11 | name = "ServerlessIntegration_INFO_TOPIC" 12 | description = "All informational messages from the ERP integration flow end up being posted here" 13 | } 14 | 15 | 16 | resource "oci_ons_subscription" "ServerlessIntegration_info_sub" { 17 | compartment_id = var.compartment_ocid 18 | endpoint = var.notification_email 19 | protocol = "EMAIL" 20 | topic_id = oci_ons_notification_topic.ServerlessIntegration_ERROR_TOPIC.id 21 | } 22 | 23 | resource "oci_ons_subscription" "ServerlessIntegration_error_sub" { 24 | compartment_id = var.compartment_ocid 25 | endpoint = var.notification_email 26 | protocol = "EMAIL" 27 | topic_id = oci_ons_notification_topic.ServerlessIntegration_INFO_TOPIC.id 28 | } 29 | -------------------------------------------------------------------------------- /terraform/functionsmodule/functions.tf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | variable "function" {} 5 | variable "compartment" {} 6 | variable "functionsapp" {} 7 | variable "application" {} 8 | variable "registry" {} 9 | 10 | locals { 11 | fnroot = "${abspath(path.root)}/${var.function.fnpath}" 12 | fnyaml = "${local.fnroot}/${var.function.yamlfile}" 13 | rawfndata = yamldecode(file(local.fnyaml)) 14 | fndata = { 15 | name = local.rawfndata.name 16 | version = local.rawfndata.version 17 | memory = local.rawfndata.memory 18 | timeout = var.function.timeout 19 | image = "${var.registry}/${local.rawfndata.name}:${local.rawfndata.version}" 20 | } 21 | } 22 | 23 | resource "null_resource" "deploy_function" { 24 | triggers = { 25 | fnversion = local.fndata.version 26 | } 27 | provisioner "local-exec" { 28 | working_dir = local.fnroot 29 | command = <<-EOC 30 | fn build 31 | fn push 32 | EOC 33 | } 34 | } 35 | 36 | resource "oci_functions_function" "test_function" { 37 | depends_on = [ null_resource.deploy_function ] 38 | application_id = var.application 39 | display_name = local.fndata.name 40 | image = local.fndata.image 41 | memory_in_mbs = local.fndata.memory 42 | timeout_in_seconds = local.fndata.timeout 43 | } 44 | 45 | output "function_ocid" { 46 | value = oci_functions_function.test_function.id 47 | } 48 | -------------------------------------------------------------------------------- /terraform/functionsapp.tf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | locals { 5 | rawctxdata = yamldecode(file(var.functionsapp.contextfile)) 6 | } 7 | resource "oci_functions_application" "ServerlessIntegration_App" { 8 | compartment_id = var.compartment_ocid 9 | syslog_url = var.functionsapp.syslogurl 10 | display_name = var.functionsapp.appname 11 | subnet_ids = [oci_core_subnet.ServerlessIntegration_subnet.id] 12 | config = jsondecode(templatefile(var.functionsapp.config_template, { 13 | apigw = oci_apigateway_gateway.ServerlessIntegration_gateway 14 | datafile_buckets= var.datafile_buckets 15 | fnapp = var.functionsapp 16 | fn = local.functionmap 17 | ons_error_topic_ocid = oci_ons_notification_topic.ServerlessIntegration_ERROR_TOPIC.id 18 | ons_info_topic_ocid = oci_ons_notification_topic.ServerlessIntegration_INFO_TOPIC.id 19 | erp_password_vault_ocid = data.oci_vault_secrets.erp_secret.secrets[0].id 20 | fusion_properties = var.fusion_properties 21 | fusion_server = var.fusion_server 22 | })) 23 | } 24 | 25 | module "functions" { 26 | source = "./functionsmodule" 27 | for_each = local.functionmap 28 | function = each.value 29 | compartment = var.compartment_ocid 30 | functionsapp = var.functionsapp 31 | application = oci_functions_application.ServerlessIntegration_App.id 32 | registry = local.rawctxdata.registry 33 | } 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /terraform/storage.tf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | # 5 | # This file creates the object storage buckets 6 | # 7 | resource "oci_objectstorage_bucket" "ServerlessIntegration_JSON_INBOUND" { 8 | compartment_id = var.compartment_ocid 9 | name = var.datafile_buckets.json_inbound_bucket_name 10 | namespace = var.oci-namespace 11 | object_events_enabled = true 12 | } 13 | resource "oci_objectstorage_bucket" "ServerlessIntegration_FAILED" { 14 | 15 | compartment_id = var.compartment_ocid 16 | name = var.datafile_buckets.failed_bucket_name 17 | namespace = var.oci-namespace 18 | object_events_enabled = true 19 | } 20 | resource "oci_objectstorage_bucket" "ServerlessIntegration_PROCESSING" { 21 | 22 | compartment_id = var.compartment_ocid 23 | name = var.datafile_buckets.processing_bucket_name 24 | namespace = var.oci-namespace 25 | object_events_enabled = true 26 | } 27 | resource "oci_objectstorage_bucket" "ServerlessIntegration_ZIPINBOUND" { 28 | compartment_id = var.compartment_ocid 29 | name = var.datafile_buckets.zip_inbound_bucket_name 30 | namespace = var.oci-namespace 31 | object_events_enabled = true 32 | } 33 | resource "oci_objectstorage_bucket" "ServerlessIntegration_SUCCESS" { 34 | compartment_id = var.compartment_ocid 35 | name = var.datafile_buckets.succeeded_bucket_name 36 | namespace = var.oci-namespace 37 | object_events_enabled = true 38 | } 39 | -------------------------------------------------------------------------------- /terraform/vault.tf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | resource "oci_kms_vault" "ServerlessIntegration_Vault" { 5 | compartment_id = var.compartment_ocid 6 | display_name= "ServerlessIntegration_Vault" 7 | vault_type = "DEFAULT" 8 | } 9 | 10 | resource "oci_kms_key" "ServerlessIntegration_Vault_Key" { 11 | compartment_id = var.compartment_ocid 12 | display_name = "ServerlessIntegration_vault_key" 13 | management_endpoint = oci_kms_vault.ServerlessIntegration_Vault.management_endpoint 14 | 15 | key_shape { 16 | algorithm = "AES" 17 | length = "16" 18 | } 19 | 20 | provisioner "local-exec" { 21 | command = <<-EOC 22 | oci vault secret create-base64 -c ${var.compartment_ocid} --secret-name "erp_password" --vault-id "${oci_kms_vault.ServerlessIntegration_Vault.id}" --key-id ${oci_kms_key.ServerlessIntegration_Vault_Key.id} --secret-content-content "${base64encode(random_password.ServerlessIntegration_FA_dummy_password.result)}" 23 | EOC 24 | } 25 | } 26 | 27 | # Generates a random password for seeding OCI 28 | resource "random_password" "ServerlessIntegration_FA_dummy_password" { 29 | length = 16 30 | special = true 31 | min_lower = 1 32 | min_upper = 1 33 | min_numeric = 1 34 | min_special = 1 35 | override_special = "!$^.," 36 | } 37 | 38 | data "oci_vault_secrets" "erp_secret" { 39 | compartment_id = var.compartment_ocid 40 | name = "erp_password" 41 | vault_id = oci_kms_vault.ServerlessIntegration_Vault.id 42 | depends_on = [oci_kms_key.ServerlessIntegration_Vault_Key] 43 | } 44 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting security vulnerabilities 2 | 3 | Oracle values the independent security research community and believes that 4 | responsible disclosure of security vulnerabilities helps us ensure the security 5 | and privacy of all our users. 6 | 7 | Please do NOT raise a GitHub Issue to report a security vulnerability. If you 8 | believe you have found a security vulnerability, please submit a report to 9 | [secalert_us@oracle.com][1] preferably with a proof of concept. Please review 10 | some additional information on [how to report security vulnerabilities to Oracle][2]. 11 | We encourage people who contact Oracle Security to use email encryption using 12 | [our encryption key][3]. 13 | 14 | We ask that you do not use other channels or contact the project maintainers 15 | directly. 16 | 17 | Non-vulnerability related security issues including ideas for new or improved 18 | security features are welcome on GitHub Issues. 19 | 20 | ## Security updates, alerts and bulletins 21 | 22 | Security updates will be released on a regular cadence. Many of our projects 23 | will typically release security fixes in conjunction with the 24 | Oracle Critical Patch Update program. Additional 25 | information, including past advisories, is available on our [security alerts][4] 26 | page. 27 | 28 | ## Security-related information 29 | 30 | We will provide security related information such as a threat model, considerations 31 | for secure use, or any known security issues in our documentation. Please note 32 | that labs and sample code are intended to demonstrate a concept and may not be 33 | sufficiently hardened for production use. 34 | 35 | [1]: mailto:secalert_us@oracle.com 36 | [2]: https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html 37 | [3]: https://www.oracle.com/security-alerts/encryptionkey.html 38 | [4]: https://www.oracle.com/security-alerts/ 39 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. 36 | -------------------------------------------------------------------------------- /terraform/network.tf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | resource "oci_core_internet_gateway" "ServerlessIntegration_igtw" { 5 | compartment_id = var.compartment_ocid 6 | vcn_id = oci_core_vcn.ServerlessIntegration_vcn.id 7 | display_name = "ServerlessIntegration_igtw" 8 | } 9 | 10 | resource "oci_core_default_route_table" "ServerlessIntegration_routetable" { 11 | manage_default_resource_id = oci_core_vcn.ServerlessIntegration_vcn.default_route_table_id 12 | display_name = "ServerlessIntegration_routetable" 13 | 14 | route_rules { 15 | destination = "0.0.0.0/0" 16 | network_entity_id = oci_core_internet_gateway.ServerlessIntegration_igtw.id 17 | } 18 | } 19 | 20 | resource "oci_core_default_security_list" "ServerlessIntegration_igtw_sec_list" { 21 | manage_default_resource_id = oci_core_vcn.ServerlessIntegration_vcn.default_security_list_id 22 | display_name = "ServerlessIntegration_seclist" 23 | egress_security_rules { 24 | protocol = "all" 25 | destination = "0.0.0.0/0" 26 | stateless = false 27 | } 28 | 29 | // allow inbound icmp traffic of a specific type 30 | ingress_security_rules { 31 | protocol = 1 32 | source = oci_core_vcn.ServerlessIntegration_vcn.cidr_block 33 | stateless = false 34 | 35 | icmp_options { 36 | type = 3 37 | } 38 | } 39 | 40 | ingress_security_rules { 41 | protocol = "6" 42 | // tcp 43 | source = "0.0.0.0/0" 44 | stateless = false 45 | 46 | tcp_options { 47 | min = 443 48 | max = 443 49 | } 50 | } 51 | } 52 | 53 | resource "oci_core_subnet" "ServerlessIntegration_subnet" { 54 | cidr_block = var.functionsapp.subnet 55 | compartment_id = var.compartment_ocid 56 | vcn_id = oci_core_vcn.ServerlessIntegration_vcn.id 57 | display_name = "ServerlessIntegration_subnet" 58 | } 59 | 60 | resource "oci_core_vcn" "ServerlessIntegration_vcn" { 61 | cidr_block = var.functionsapp.subnet 62 | compartment_id = var.compartment_ocid 63 | display_name = "ServerlessIntegration_VCN" 64 | } 65 | -------------------------------------------------------------------------------- /functions/erp-callback/samplePayloads/jsoncallback.json: -------------------------------------------------------------------------------- 1 | { 2 | "JOBS": [ 3 | { 4 | "JOBNAME": "Load Interface File for 5 | Import 6 | "," 7 | JOBPATH 8 | ":" 9 | /oracle/apps/ess/financials/commonModules/shared/common/interfaceLoader 10 | "," 11 | DOCUMENTNAME 12 | ":" 13 | apinvoiceimport.zip 14 | "," 15 | REQUESTID 16 | ":" 17 | 1697815 18 | "," 19 | STATUS 20 | ":" 21 | SUCCEEDED 22 | "," 23 | CHILD 24 | ":[{" 25 | JOBNAME 26 | ":" 27 | Load 28 | File 29 | to 30 | Interface 31 | "," 32 | JOBPATH 33 | ":" 34 | /oracle/apps/ess/financials/commonModules/shared/common/interfaceLoader 35 | "," 36 | REQUESTID 37 | ":" 38 | 1697818 39 | "," 40 | STATUS 41 | ":" 42 | SUCCEEDED 43 | "},{" 44 | JOBNAME 45 | ":" 46 | Load 47 | File 48 | to 49 | Interface 50 | "," 51 | JOBPATH 52 | ":" 53 | /oracle/apps/ess/financials/commonModules/shared/common/interfaceLoader 54 | "," 55 | REQUESTID 56 | ":" 57 | 1697817 58 | "," 59 | STATUS 60 | ":" 61 | SUCCEEDED 62 | "},{" 63 | JOBNAME 64 | ":" 65 | Transfer 66 | File 67 | "," 68 | JOBPATH 69 | ":" 70 | /oracle/apps/ess/financials/commonModules/shared/common/interfaceLoader 71 | "," 72 | REQUESTID 73 | ":" 74 | 1697816 75 | "," 76 | STATUS 77 | ":" 78 | SUCCEEDED 79 | "}]},{" 80 | JOBNAME 81 | ":" 82 | Import 83 | Payables 84 | Invoices 85 | "," 86 | JOBPATH 87 | ":" 88 | /oracle/apps/ess/financials/payables/invoices/transactions 89 | "," 90 | REQUESTID 91 | ":" 92 | 1697819 93 | "," 94 | STATUS 95 | ":" 96 | SUCCEEDED 97 | "}]," 98 | SUMMARYSTATUS 99 | ":" 100 | SUCCEEDED 101 | "} 102 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to this repository 2 | 3 | We welcome your contributions! There are multiple ways to contribute. 4 | 5 | ## Opening issues 6 | 7 | For bugs or enhancement requests, please file a GitHub issue unless it's 8 | security related. When filing a bug remember that the better written the bug is, 9 | the more likely it is to be fixed. If you think you've found a security 10 | vulnerability, do not raise a GitHub issue and follow the instructions in our 11 | [security policy](./SECURITY.md). 12 | 13 | ## Contributing code 14 | 15 | We welcome your code contributions. Before submitting code via a pull request, 16 | you will need to have signed the [Oracle Contributor Agreement][OCA] (OCA) and 17 | your commits need to include the following line using the name and e-mail 18 | address you used to sign the OCA: 19 | 20 | ```text 21 | Signed-off-by: Your Name 22 | ``` 23 | 24 | This can be automatically added to pull requests by committing with `--sign-off` 25 | or `-s`, e.g. 26 | 27 | ```text 28 | git commit --signoff 29 | ``` 30 | 31 | Only pull requests from committers that can be verified as having signed the OCA 32 | can be accepted. 33 | 34 | ## Pull request process 35 | 36 | 1. Ensure there is an issue created to track and discuss the fix or enhancement 37 | you intend to submit. 38 | 1. Fork this repository. 39 | 1. Create a branch in your fork to implement the changes. We recommend using 40 | the issue number as part of your branch name, e.g. `1234-fixes`. 41 | 1. Ensure that any documentation is updated with the changes that are required 42 | by your change. 43 | 1. Ensure that any samples are updated if the base image has been changed. 44 | 1. Submit the pull request. *Do not leave the pull request blank*. Explain exactly 45 | what your changes are meant to do and provide simple steps on how to validate. 46 | your changes. Ensure that you reference the issue you created as well. 47 | 1. We will assign the pull request to 2-3 people for review before it is merged. 48 | 49 | ## Code of conduct 50 | 51 | Follow the [Golden Rule](https://en.wikipedia.org/wiki/Golden_Rule). If you'd 52 | like more specific guidelines, see the [Contributor Covenant Code of Conduct][COC]. 53 | 54 | [OCA]: https://oca.opensource.oracle.com 55 | [COC]: https://www.contributor-covenant.org/version/1/4/code-of-conduct/ 56 | -------------------------------------------------------------------------------- /terraform/events.tf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | resource "oci_events_rule" "ServerlessIntegration_PROCESS_ERP_JSON" { 5 | actions { 6 | actions { 7 | action_type = "FAAS" 8 | is_enabled = "true" 9 | function_id= module.functions["erp-transform-file"].function_ocid 10 | description = "Call erp-transform-file to transform the file from JSON to ERP format" 11 | } 12 | actions { 13 | action_type = "ONS" 14 | is_enabled = "true" 15 | description = "Send Notification" 16 | topic_id = oci_ons_notification_topic.ServerlessIntegration_INFO_TOPIC.id 17 | } 18 | } 19 | compartment_id = var.compartment_ocid 20 | condition = jsonencode({ 21 | eventType: "com.oraclecloud.objectstorage.createobject" 22 | data: { additionalDetails: { 23 | bucketName: var.datafile_buckets.json_inbound_bucket_name 24 | } 25 | } 26 | } 27 | ) 28 | 29 | 30 | 31 | 32 | 33 | display_name = "ServerlessIntegration_PROCESS_ERP JSON" 34 | is_enabled =true 35 | } 36 | 37 | resource "oci_events_rule" "ServerlessIntegration_PROCESS_ERP_ZIP" { 38 | actions { 39 | actions { 40 | action_type = "FAAS" 41 | is_enabled = "true" 42 | function_id= module.functions["erp-file-load"].function_ocid 43 | description = "Call erp-file=load to load the file into Oracle ERP" 44 | } 45 | actions { 46 | action_type = "ONS" 47 | is_enabled = "true" 48 | description = "Send Notification" 49 | topic_id = oci_ons_notification_topic.ServerlessIntegration_INFO_TOPIC.id 50 | } 51 | } 52 | compartment_id = var.compartment_ocid 53 | condition = jsonencode({ 54 | eventType: "com.oraclecloud.objectstorage.createobject" 55 | data: { additionalDetails: { 56 | bucketName: var.datafile_buckets.zip_inbound_bucket_name 57 | } 58 | } 59 | } 60 | ) 61 | 62 | 63 | display_name = "ServerlessIntegration_PROCESS_ERP_ZIP" 64 | is_enabled =true 65 | } -------------------------------------------------------------------------------- /functions/erp-transform-file/erp_data_file.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | 5 | import zipfile 6 | import io 7 | import logging 8 | 9 | 10 | def create_erp_invoices_datafiles(json_data, zip_file_name): 11 | logging.info("Within create_erp_invoices_datafiles function") 12 | invoice_template = open('APInvoiceTemplate.csv.template', 'r').read() 13 | invoice_line_template = open('APInvoiceLinesTemplate.csv.template', 'r').read() 14 | 15 | # Now process the file 16 | ap_invoices_interface = "" 17 | ap_invoice_lines_interface = "" 18 | 19 | for single_invoice in json_data['invoices']: 20 | new_invoice = invoice_template 21 | for invoice_key, invoice_key_value in single_invoice.items(): 22 | if invoice_key.upper() == "INVOICELINES": 23 | # Process Invoice Lines 24 | line_number = 1 # Set line number 1 and increment for each invoiceline 25 | for invoice_line in invoice_key_value: 26 | # Process MANDATORY Elements in Invoice Line 27 | # Get new template object 28 | new_invoice_line = invoice_line_template 29 | # Set Linenumber, Invoice ID, $ACCOUNTINGDATE 30 | new_invoice_line = new_invoice_line.replace("$INVOICELINENUM", str(line_number)) 31 | line_number = line_number + 1 32 | new_invoice_line = new_invoice_line.replace("$ACCOUNTINGDATE", single_invoice['accountingDate']) 33 | new_invoice_line = new_invoice_line.replace("$INVOICEID", single_invoice['invoiceId']) 34 | 35 | # Now process invoice lines 36 | for invoice_lines_key, invoice_lines_value in invoice_line.items(): 37 | new_invoice_line = new_invoice_line.replace(f'${invoice_lines_key.upper()}', 38 | f'{invoice_lines_value}') 39 | ap_invoice_lines_interface = ap_invoice_lines_interface + new_invoice_line 40 | else: 41 | # Process Invoices 42 | new_invoice = new_invoice.replace(f'${invoice_key.upper()}', f'{invoice_key_value}') 43 | ap_invoices_interface = ap_invoices_interface + new_invoice 44 | 45 | logging.info("Processed data") 46 | logging.info("AP_INVOICES_INTERFACE") 47 | logging.info(ap_invoices_interface) 48 | logging.info("AP_INVOICE_LINES_INTERFACE") 49 | logging.info(ap_invoice_lines_interface) 50 | 51 | # Write data to zip file. 52 | # Due to limits of disk space in Functions, the zip file is created on the fly. 53 | zip_buffer = io.BytesIO() 54 | destination_zip_name = f'{zip_file_name}' 55 | with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED, False) as zip_file: 56 | for file_name, json_data in [('ApInvoicesInterface.csv', io.BytesIO(ap_invoices_interface.encode())), 57 | ('ApInvoiceLinesInterface.csv', io.BytesIO(ap_invoice_lines_interface.encode()))]: 58 | zip_file.writestr(file_name, json_data.getvalue()) 59 | 60 | with open(destination_zip_name, 'wb') as f: 61 | f.write(zip_buffer.getvalue()) 62 | 63 | logging.info(f'Zip file writen to {destination_zip_name}') -------------------------------------------------------------------------------- /functions/erp-callback/samplePayloads/sampleCallback.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | https://xxxxx.xxx.us-phoenix-1.oci.customer-oci.com/erpcallback/callback 8 | 9 | http://xmlns.oracle.com/scheduler/ESSWebService/getCompletionStatus/Response 10 | urn:uuid:xxxx 11 | urn:uuid:xxxxx 12 | 13 | http://www.w3.org/2005/08/addressing/anonymous 14 | 15 | 17 | 20 | 21 | 23 | 24 | 25 | CASEY.BROWN 26 | 27 | 28 | urn:oasis:names:tc:SAML:1.0:cm:bearer 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | xxxx/xxxx= 43 | 44 | 45 | 46 | xxxxx 47 | 48 | 49 | 50 | 51 | xxxxxx 52 | 53 | 54 | CN=xx-2, DC=cloud, DC=oracle, DC=com 55 | xxxx 56 | 57 | CN=xx, DC=cloud, DC=oracle, DC=com 58 | xxxx= 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 1726027 68 | SUCCEEDED 69 | {"JOBS":[{"JOBNAME":"Load Interface File for 70 | Import","JOBPATH":"/oracle/apps/ess/financials/commonModules/shared/common/interfaceLoader","DOCUMENTNAME":"createInvoiceSample.zip","REQUESTID":"1726027","STATUS":"SUCCEEDED","CHILD":[{"JOBNAME":"Load 71 | File to 72 | Interface","JOBPATH":"/oracle/apps/ess/financials/commonModules/shared/common/interfaceLoader","REQUESTID":"1726027","STATUS":"SUCCEEDED"},{"JOBNAME":"Load 73 | File to 74 | Interface","JOBPATH":"/oracle/apps/ess/financials/commonModules/shared/common/interfaceLoader","REQUESTID":"1726027","STATUS":"SUCCEEDED"},{"JOBNAME":"Transfer 75 | File","JOBPATH":"/oracle/apps/ess/financials/commonModules/shared/common/interfaceLoader","REQUESTID":"1726027","STATUS":"SUCCEEDED"}]},{"JOBNAME":"Import 76 | Payables 77 | Invoices","JOBPATH":"/oracle/apps/ess/financials/payables/invoices/transactions","REQUESTID":"1697819","STATUS":"SUCCEEDED"}],"SUMMARYSTATUS":"SUCCEEDED"} 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /terraform/variables.tf: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | 5 | variable "user" { 6 | description = "OCI user OCID" 7 | type = string 8 | } 9 | variable "fingerprint" { 10 | description = "OCI key fingerprint" 11 | type = string 12 | 13 | } 14 | variable "key_file" { 15 | description = "OCI key file path" 16 | type = string 17 | } 18 | variable "tenancy" { 19 | description = "OCI tenancy OCID" 20 | type = string 21 | } 22 | variable "region" { 23 | description = "OCI region code" 24 | type = string 25 | } 26 | 27 | variable "pass_phrase" { 28 | description = "OCI key file pass phrase" 29 | type = string 30 | default = null 31 | } 32 | 33 | variable "functionsapp" { 34 | description = <func} 104 | } 105 | 106 | provider "oci" { 107 | tenancy_ocid = var.tenancy 108 | user_ocid = var.user 109 | fingerprint = var.fingerprint 110 | private_key_path = var.key_file 111 | region = var.region 112 | private_key_password = var.pass_phrase 113 | } 114 | 115 | variable "compartment_ocid" { 116 | description = "OCI compartment OCID" 117 | type = string 118 | } 119 | 120 | variable "oci-namespace" { 121 | description = "OCI Namespace where assets will be deployed to" 122 | type = string 123 | } 124 | 125 | 126 | # Email address to receive notifications 127 | variable "notification_email" { 128 | description = "Email to send notifications whilst code is processing data" 129 | type = string 130 | } 131 | 132 | # 133 | # Bucket Names used for the data files, the following names will be "prefixed" with the global prefix above 134 | # 135 | variable "datafile_buckets" { 136 | description = "Names of the various OCI buckets" 137 | type = object( 138 | { 139 | json_inbound_bucket_name=string 140 | zip_inbound_bucket_name=string 141 | processing_bucket_name=string 142 | succeeded_bucket_name=string 143 | failed_bucket_name=string 144 | }) 145 | default = { 146 | json_inbound_bucket_name = "Serverless_Integration_json_inbound" 147 | zip_inbound_bucket_name = "Serverless_Integration_zip_inbound" 148 | processing_bucket_name = "Serverless_Integration_processing" 149 | succeeded_bucket_name = "Serverless_Integration_succeeded" 150 | failed_bucket_name = "Serverless_Integration_failed" 151 | } 152 | } 153 | 154 | 155 | # 156 | # Fusion ERP FBDI defaults (for invoices) 157 | variable "fusion_properties" { 158 | description = < object: 178 | """ 179 | 180 | :rtype: object 181 | """ 182 | message = {"status": status, 183 | "header": title, 184 | "message": message, 185 | "additionalDetails": additional_details} 186 | publish_ons_notification(ons_topic_id, title, str(message)) 187 | return message 188 | -------------------------------------------------------------------------------- /functions/erp-transform-file/func.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | 5 | import logging 6 | import io 7 | import json 8 | 9 | import oci.object_storage 10 | from fdk import response 11 | import erp_data_file 12 | 13 | 14 | def handler(ctx, data: io.BytesIO = None): 15 | logging.info("------------------------------------------------------------------------------") 16 | logging.info("Within erp-transform-file") 17 | logging.info("------------------------------------------------------------------------------") 18 | 19 | oci_signer = oci.auth.signers.get_resource_principals_signer() 20 | object_storage_client = oci.object_storage.ObjectStorageClient(config={}, signer=oci_signer) 21 | namespace = object_storage_client.get_namespace().data 22 | 23 | # Get Configuration Parameters 24 | cfg = ctx.Config() 25 | 26 | try: 27 | param_json_inbound_bucket_name = cfg['json_inbound_bucket_name'] 28 | param_zip_inbound_bucket_name = cfg["zip_inbound_bucket_name"] 29 | 30 | param_ons_error_topic_ocid = cfg["ons_error_topic_ocid"] 31 | param_ons_info_topic_ocid = cfg["ons_info_topic_ocid"] 32 | 33 | except KeyError as ke: 34 | message = f'Mandatory Configuration Parameter {ke} missing, please check all configuration parameters' 35 | return return_fn_error(ctx, response, message) 36 | 37 | try: 38 | body = json.loads(data.getvalue()) 39 | except json.decoder.JSONDecodeError as ex: 40 | 41 | message = send_notification(ons_topic_id=param_ons_error_topic_ocid, 42 | title="JSON Exception", 43 | message="JSON Exception Parsing input data file", 44 | status="ERROR", 45 | additional_details=str(ex) 46 | ) 47 | 48 | return return_fn_error(ctx, response, message) 49 | 50 | if body["eventType"] != "com.oraclecloud.objectstorage.createobject": 51 | message = f'eventType not of com.oraclecloud.objectstorage.createobject aborting' 52 | 53 | message = send_notification(ons_topic_id=param_ons_info_topic_ocid, 54 | title="Incorrect Event", 55 | message="Incorrect EventType Received", 56 | status="ERROR", 57 | additional_details=body) 58 | return return_fn_error(ctx, response, message) 59 | 60 | json_datafile_name = body['data']['resourceName'] 61 | logging.info(f'Data File received = {json_datafile_name}') 62 | 63 | # Read datafile from OCI 64 | json_data_file = object_storage_client.get_object(namespace, param_json_inbound_bucket_name, json_datafile_name) 65 | if json_data_file.status != 200: 66 | msg = f'Unable to read Data File [{json_datafile_name} from bucket [{param_json_inbound_bucket_name}' 67 | additional_details = {"jsonDataFilename": json_datafile_name} 68 | message = send_notification( 69 | ons_topic_id=param_ons_info_topic_ocid, 70 | title="Data File Read Error", 71 | message=msg, 72 | status="ERROR", 73 | additional_details=additional_details) 74 | 75 | return return_fn_error(ctx, response, message, json.dumps(additional_details)) 76 | try: 77 | json_data = json.loads(json_data_file.data.content.decode('UTF8')) 78 | except json.decoder.JSONDecodeError as ex: 79 | 80 | additional_details={ 81 | "jsonDecodeError": str(ex), 82 | "filename" : json_datafile_name 83 | } 84 | message = send_notification(ons_topic_id=param_ons_error_topic_ocid, 85 | title="JSON Decode Exception", 86 | message="JSON Decode Exception Parsing input data file, please check the file", 87 | status="ERROR", 88 | additional_details=additional_details 89 | ) 90 | return return_fn_error(ctx, response, message) 91 | # Write result to /tmp 92 | transformed_data_file = "/tmp/ " + json_datafile_name 93 | erp_data_file.create_erp_invoices_datafiles(json_data, transformed_data_file) 94 | 95 | # Write resulting object to json_inbound_bucket_name, no change extension , enroute 96 | with open(transformed_data_file, 'rb') as f: 97 | oci_response = object_storage_client.put_object(namespace, param_zip_inbound_bucket_name, 98 | json_datafile_name.replace('.json', '.zip'), f) 99 | if oci_response.status != 200: 100 | message = f'Error loading file into OCI bucket {json_datafile_name}' 101 | additional_details = {"jsonDataFilename": json_datafile_name} 102 | 103 | message = send_notification( 104 | ons_topic_id=param_ons_info_topic_ocid, 105 | title="Data Bucket LoadError", 106 | message="Received error whilst writing file to OCI bucket", 107 | status="ERROR", 108 | additional_details=additional_details) 109 | 110 | return return_fn_error(ctx, response, message, json.dumps(additional_details)) 111 | 112 | # Now delete file as its been processed 113 | if object_storage_client.delete_object(namespace, param_json_inbound_bucket_name, json_datafile_name).status != 204: 114 | message_details = f'Error deleting processed file {json_datafile_name} into OCI bucket ' 115 | additional_details = {"jsonDataFilename": json_datafile_name} 116 | message = send_notification( 117 | ons_topic_id=param_ons_error_topic_ocid, 118 | title="Failed to Delete Tranform file", 119 | message=message_details, 120 | status="ERROR", 121 | additional_details=additional_details) 122 | return return_fn_error(ctx, response, message, json.dumps(additional_details)) 123 | 124 | # Publish Success Message 125 | ons_body = {"message": "ERP Transform of file " + json_datafile_name + " completed", 126 | "filename": json_datafile_name} 127 | additional_details = "" 128 | message = send_notification( 129 | ons_topic_id=param_ons_info_topic_ocid, 130 | title=f'Transform of file {json_datafile_name} Completed ', 131 | message=ons_body, 132 | status="INFO", 133 | additional_details=additional_details) 134 | 135 | return response.Response( 136 | ctx, response_data=json.dumps( 137 | { 138 | "message": f'Datafile [{json_datafile_name}] transformed and put into bucket [{param_zip_inbound_bucket_name}]'}), 139 | headers={"Content-Type": "application/json"} 140 | 141 | ) 142 | 143 | 144 | def return_fn_error(ctx, fn_response, message, additional_details="None"): 145 | logging.critical(message) 146 | # Return Error 147 | 148 | return fn_response.Response( 149 | ctx, response_data= 150 | { 151 | "errorMessage": message, 152 | "additionalDetails": additional_details 153 | }, 154 | headers={"Content-Type": "application/json"} 155 | ) 156 | 157 | 158 | # 159 | # Helper functions 160 | # 161 | def publish_ons_notification(topic_id, msg_title, msg_body): 162 | try: 163 | signer = oci.auth.signers.get_resource_principals_signer() 164 | logging.info("Publish notification, topic id" + topic_id) 165 | client = oci.ons.NotificationDataPlaneClient({}, signer=signer) 166 | msg = oci.ons.models.MessageDetails(title=msg_title, body=msg_body) 167 | client.publish_message(topic_id, msg) 168 | except oci.exceptions.ServiceError as serr: 169 | logging.critical(f'Exception sending notification {0} to OCI, is the OCID of the notification correct? {serr}') 170 | except Exception as err: 171 | logging.critical(f'Unknown exception occurred when sending notification, please see log {err}') 172 | 173 | 174 | def send_notification(ons_topic_id, title, message, status, additional_details) -> object: 175 | message = {"status": status, 176 | "header": title, 177 | "message": message, 178 | "additionalDetails": additional_details} 179 | publish_ons_notification(ons_topic_id, title, str(message)) 180 | return message 181 | -------------------------------------------------------------------------------- /functions/erp-file-load/func.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 | 4 | 5 | 6 | import logging 7 | import io 8 | import json 9 | import base64 10 | from fdk import response 11 | import oci.object_storage 12 | import requests 13 | 14 | JSON_CONTENT_TYPE = "application/json" 15 | 16 | class FA_REST_Exception(Exception): 17 | def __init__(self, message): 18 | self.message = message 19 | 20 | def handler(ctx, data: io.BytesIO = None): 21 | logging.info("------------------------------------------------------------------------------") 22 | logging.info("Within load-file-erp function") 23 | logging.info("------------------------------------------------------------------------------") 24 | 25 | signer = oci.auth.signers.get_resource_principals_signer() 26 | object_storage_client = oci.object_storage.ObjectStorageClient(config={}, signer=signer) 27 | namespace = object_storage_client.get_namespace().data 28 | 29 | # Get Configuration Parameters 30 | cfg = ctx.Config() 31 | try: 32 | param_inbound_bucket_name = cfg["zip_inbound_bucket_name"] 33 | param_processing_bucket_name = cfg["processing_bucket_name"] 34 | param_erp_url = cfg["erp_url"] 35 | param_erp_username = cfg["erp_username"] 36 | param_oci_password_vault_ocid = cfg["erp_password_vault_ocid"] 37 | 38 | param_fa_jobname = cfg['erp_jobname'] 39 | param_fa_paramlist = cfg['erp_paramlist'] 40 | param_fa_callback_url = cfg['erp_callback_url'] 41 | 42 | param_ons_error_topic_ocid = cfg["ons_error_topic_ocid"] 43 | param_ons_info_topic_ocid = cfg["ons_info_topic_ocid"] 44 | except KeyError as ke: 45 | message = f'Mandatory Configuration Parameter {ke} missing, please check all configuration parameters' 46 | return return_fn_error(ctx, response, message) 47 | 48 | # Check we've received the right type of event 49 | body = json.loads(data.getvalue()) 50 | logging.info("---------------------------------------------------------") 51 | logging.info(f'Contents of event body is {str(body)}') 52 | logging.info("---------------------------------------------------------") 53 | 54 | if body["eventType"] != "com.oraclecloud.objectstorage.createobject": 55 | message = send_notification( 56 | ons_topic_id=param_ons_error_topic_ocid, 57 | title="Event Type Error", 58 | message="Function called with incorrect event type, eventType should be com.oraclecloud.objectstorage.createobject", 59 | status="ERROR", 60 | additional_details=body) 61 | 62 | return return_fn_error(ctx, response, message) 63 | 64 | data_file_name = body['data']['resourceName'] 65 | logging.info(f'Data File = {data_file_name}') 66 | 67 | # Read Object 68 | try: 69 | data_file = object_storage_client.get_object(namespace, param_inbound_bucket_name, data_file_name) 70 | except oci.exceptions.ServiceError as ex: 71 | message = send_notification( 72 | ons_topic_id=param_ons_error_topic_ocid, 73 | title="File Read Error", 74 | message="Failed to load file from OCI storage", 75 | status="ERROR", 76 | additional_details=data_file_name 77 | ) 78 | logging.info(message) 79 | return return_fn_error(ctx, response, message) 80 | logging.info(f'Success: File {data_file_name} was retrieved') 81 | 82 | 83 | # GET FA details from OCI Vault 84 | try: 85 | logging.info(f"oci vaultID={param_oci_password_vault_ocid}") 86 | param_erp_password = read_secret_value(signer, param_oci_password_vault_ocid) 87 | except oci.exceptions.ServiceError as ex: 88 | if ex is None: 89 | ex = "NoError" 90 | logging.critical("Error getting erp password") 91 | additional_details = {"vaultOCID": param_oci_password_vault_ocid, 92 | "error": str(ex) 93 | } 94 | message = send_notification( 95 | ons_topic_id=param_ons_error_topic_ocid, 96 | title="FA Password Error", 97 | message="Error obtaining Fusion FA Password from OCI Vault", 98 | status="ERROR", 99 | additional_details=additional_details) 100 | return return_fn_error(ctx, response, message) 101 | 102 | param_erp_auth = (param_erp_username, param_erp_password) 103 | 104 | base64_encoded_file = base64.b64encode(data_file.data.content).decode('UTF8') 105 | 106 | saas_result = erpimport_bulk_data(param_erp_url, param_erp_auth, base64_encoded_file, data_file_name, 107 | param_fa_jobname, 108 | param_fa_paramlist, param_fa_callback_url) 109 | 110 | erp_job_id = saas_result["ReqstId"] 111 | logging.info(f'ERP Job number {erp_job_id} submitted') 112 | 113 | # Copy object to processing bucket, renaming file as we go 114 | put_object_response = object_storage_client.put_object(namespace, param_processing_bucket_name, 115 | data_file_name + "_ERPJOBID_" + erp_job_id, 116 | data_file.data.content) 117 | logging.info(f'Response of put file to destination bucket {put_object_response.status}') 118 | if put_object_response.status == 200: 119 | # If all good then delete original object 120 | delete_result = object_storage_client.delete_object(namespace, param_inbound_bucket_name, data_file_name) 121 | if delete_result.status != 204: 122 | # Error moving files is more of a warning than error.... 123 | message = f'Warning : Error deleting file {data_file_name} from {param_inbound_bucket_name}' 124 | logging.info(message) 125 | additional_details = { 126 | "filename": data_file_name, 127 | "sourceBucket": param_inbound_bucket_name, 128 | "destinationBucket": param_processing_bucket_name 129 | } 130 | send_notification( 131 | ons_topic_id=param_ons_info_topic_ocid, 132 | title="Error moving data file in OCI", 133 | message=message, 134 | status="WARNING", 135 | additional_details=additional_details) 136 | else: 137 | # Error moving files is more of a warning than error.... 138 | message = f'Warning Unable to copy {data_file_name} from {param_inbound_bucket_name} to {param_processing_bucket_name} bucket, leaving original file' 139 | additional_details = { 140 | "filename": data_file_name, 141 | "sourceBucket": param_inbound_bucket_name, 142 | "destinationBucket": param_processing_bucket_name 143 | } 144 | send_notification( 145 | ons_topic_id=param_ons_info_topic_ocid, 146 | title="Error moving data file in OCI", 147 | message=message, 148 | status="WARNING", 149 | additional_details=additional_details) 150 | logging.info(message) 151 | logging.debug(f' Result from SaaS ') 152 | logging.debug(saas_result) 153 | 154 | # Publish successful load message to info topic 155 | additional_details = {"filename": data_file_name, 156 | "erpJobId": erp_job_id, 157 | "saasResponse": saas_result 158 | } 159 | 160 | message = send_notification( 161 | ons_topic_id=param_ons_info_topic_ocid, 162 | title="Successfully Loaded Data to SaaS", 163 | message="Successfully Loaded Datafile to ERP", 164 | status="INFO", 165 | additional_details=additional_details) 166 | 167 | # Return result from SaaS as response 168 | return response.Response( 169 | ctx, 170 | response_data=json.dumps(message), 171 | headers={"Content-Type": JSON_CONTENT_TYPE} 172 | ) 173 | 174 | 175 | def erpimport_bulk_data(param_erp_url, param_erp_auth, base64_encoded_file, data_file_name, jobname, paramlist, 176 | param_fa_callback_url): 177 | # Send file to ERP 178 | 179 | erp_payload = { 180 | "OperationName": "importBulkData", 181 | "DocumentContent": base64_encoded_file, 182 | "ContentType": "zip", 183 | "FileName": data_file_name, 184 | "JobName": jobname, 185 | "ParameterList": paramlist, 186 | "CallbackURL": param_fa_callback_url, 187 | "NotificationCode": "10" 188 | } 189 | logging.info(f'Sending file to erp with payload {erp_payload}') 190 | result = requests.post( 191 | url=param_erp_url, 192 | auth=param_erp_auth, 193 | headers={"Content-Type": JSON_CONTENT_TYPE}, 194 | json=erp_payload 195 | ) 196 | 197 | if result.status_code != 201: 198 | message = "Error " + str(result.status_code) + " occurred during upload. Message=" + str(result.content) 199 | raise FA_REST_Exception("Error " + message) 200 | 201 | # Return result for future processing 202 | return result.json() 203 | 204 | 205 | def return_fn_error(ctx, fn_response, message, additional_data="None"): 206 | logging.critical(message) 207 | # Return Error 208 | 209 | return fn_response.Response( 210 | ctx, response_data=json.dumps( 211 | { 212 | "errorMessage": message, 213 | "additionalData": additional_data 214 | }), 215 | headers={"Content-Type": JSON_CONTENT_TYPE} 216 | ) 217 | 218 | 219 | def read_secret_value(signer, secret_id): 220 | 221 | secret_client = oci.secrets.SecretsClient(config={}, signer=signer) 222 | secret_response = secret_client.get_secret_bundle(secret_id) 223 | base64_secret_content = secret_response.data.secret_bundle_content.content 224 | base64_secret_bytes = base64_secret_content.encode('ascii') 225 | base64_message_bytes = base64.b64decode(base64_secret_bytes) 226 | secret_content = base64_message_bytes.decode('ascii') 227 | return secret_content 228 | 229 | 230 | # 231 | # Helper functions 232 | # 233 | def publish_ons_notification(topic_id, msg_title, msg_body): 234 | try: 235 | signer = oci.auth.signers.get_resource_principals_signer() 236 | logging.info("Publish notification, topic id" + topic_id) 237 | client = oci.ons.NotificationDataPlaneClient({}, signer=signer) 238 | msg = oci.ons.models.MessageDetails(title=msg_title, body=msg_body) 239 | client.publish_message(topic_id, msg) 240 | except oci.exceptions.ServiceError as serr: 241 | logging.critical(f'Exception sending notification {0} to OCI, is the OCID of the notification correct? {serr}') 242 | except Exception as err: 243 | logging.critical(f'Unknown exception occurred when sending notification, please see log {err}') 244 | 245 | 246 | def send_notification(ons_topic_id, title, message, status, additional_details) -> object: 247 | """ 248 | 249 | :rtype: object 250 | """ 251 | message = {"status": status, 252 | "header": title, 253 | "message": message, 254 | "additionalDetails": additional_details} 255 | publish_ons_notification(ons_topic_id, title, str(message)) 256 | return message 257 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Serverless SaaS ERP Data Loading 2 | 3 | ## Introduction 4 | 5 | This solution shows how you can use components in Oracle Cloud Infrastructure (OCI) to build a serverless data loading solution for Oracle Fusion ERP. This solution specifically targets components such as OCI Cloud Functions, Object Storage buckets, OCI Events and Event rules and OCI Notifications to provide a serverless solution where data can be loaded into Oracle Fusion ERP by simply placing a simplified JSON file into a Storage bucket. 6 | 7 | This solution has a number of advantages over traditional solutions 8 | 9 | - When not being used, no services are running and therefore are at zero cost to the customer 10 | - No server upgrades required 11 | - No server patches required 12 | - All password secrets are stored safely within secure OCI Vaults 13 | - Scaling up/down is automatically done by the serverless framework 14 | 15 | The core components of this solution comprises of three serverless Oracle Cloud Functions : 16 | 17 | 1. Transformation function : This cloud function transforms an incoming JSON Payload into the ERP (invoices) specific format and wraps the files into a single ZIP file. The ZIP file is then stored on OCI Object Storage for future processing 18 | 2. Data Loading function : This function loads the data from OCI Object Storage and loads it into Oracle Fusion ERP 19 | 3. A call-back processing function : This function waits for a call-back from Oracle Fusion and then parses it to see if it succeeded or failed. 20 | 21 | For more information please refer to the blog article on [A-Team Chronicles]( https://www.ateam-oracle.com/loading-data-into-oracle-fusion-saas-serverless-style-v2) 22 | 23 | ### Services / libraries used in this sample 24 | 25 | - [Oracle Fusion ERP](https://www.oracle.com/uk/erp/) (Release 20B+) 26 | - Oracle Cloud Infrastructure 27 | - [Oracle Cloud Functions](https://www.oracle.com/uk/cloud-native/functions/) 28 | - [Oracle Cloud Events](https://www.oracle.com/uk/cloud-native/events-service/) 29 | - [Oracle Cloud Notifications](https://www.oracle.com/uk/devops/notifications/) 30 | - [Oracle Cloud Vault](https://www.oracle.com/uk/security/cloud-security/key-management/) 31 | - [HashiCorp Terraform (0.13+)](https://www.Terraform.io/) 32 | - [Oracle Terraform Provider](https://registry.Terraform.io/providers/hashicorp/oci/latest/docs) 33 | - Python 3.8+ 34 | - [Python OCI SDK (2.23+)](https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/) 35 | - [Python Requests library (2.24+)](https://requests.readthedocs.io/en/master/) 36 | - [Oracle Cloud Functions Developer Kit (Python)](https://github.com/fnproject/fdk-python) 37 | 38 | ### Features / patterns demonstrated in this sample 39 | 40 | - Serverless solution 41 | - Demonstrates how to deploy the entire solution to OCI using Terraform 42 | - Specific call out showing how to deploy Oracle Cloud Functions to OCI using Terraform scripts 43 | - Storing Oracle passwords securely within the OCI vault and retrieving them using Python code 44 | - Reading/writing data to OCI Storage buckets 45 | - Sending notifications to users 46 | - Capturing OCI Events and launching Oracle Cloud Functions based on predetermined events 47 | - Loading data into Oracle Fusion applications via the integration REST API 48 | - Transforming a JSON structure into a Oracle ERP cloud compatible data file 49 | 50 | ## Solution architecture 51 | 52 | ![Architecture](images/architecture.jpg) 53 | 54 | When a file is inserted into the processing bucket a OCI event is emitted by OCI. This event is configured to call a serverless cloud function which transforms the file from a simplified JSON format to the specific format required by Oracle Fusion ERP. An event can be used to launch multiple actions, calling Oracle Cloud Functions is one action, sending notifications is another. Once the cloud function has finished processing the file it inserts the file into a new storage bucket and then the next phase of loading the data proceeds. 55 | 56 | A short video describing this architecture can be found on YouTube at this link [ERP data load using Serverless Technologies](https://www.youtube.com/watch?v=Ffq15paItsQ) 57 | 58 | ## Installation 59 | 60 | ### Pre-requisites 61 | 62 | 1. Ensure Oracle Cloud Functions is installed and that you can deploy a simple Python based cloud function. If you haven't already installed and configured Oracle Cloud Functions then we can recommend going through the [Oracle Cloud Functions quickstart ](https://www.oracle.com/webfolder/technetwork/tutorials/infographics/oci_faas_gettingstarted_quickview/functions_quickview_top/functions_quickview/index.html) as this will not only help you setup and configure your environment but also show you how to deploy some sample Oracle Cloud Functions. 63 | 2. Ensure Terraform is installed and you are able to deploy OCI components to OCI (eg. create a storage bucket) 64 | 3. Ensure Fusion Applications is functionally set up to accept the data you are looking to load 65 | 66 | ### Creating the cloud artefacts in OCI cloud 67 | 68 | 1. Navigate to the `terraform` directory 69 | 70 | 2. Edit/create new `terraform/config.auto.tfvars ` file entering parameters based on your system preferences. This file contains system wide specific variables needed for the solution to work and you can use the `config.auto.tfvars.template` as a template for this file 71 | 72 | 3. Edit/create new `terraform/oci.auto.tfvars`. This file contains OCI system specific variables needed for the solution to communicate with OCI. This file can be copied from your $HOME/.oci/config file, without the section header. You can use the `oci_config.auto.tfvars.template` as a template for this file 73 | 74 | 4. Edit/create a new `terraform/terraform.tfvars` file using `Terraform.tfvars.template` as a template file 75 | 76 | 5. Within `variables.tf` make sure you modify the `erp_paramlist` so that it matches your systems functional setup (e.g. Business Unit Id). If you want to load different objects, i.e. other than invoices, then you will also need to modify `erp_jobname` to match your Oracle Fusion configuration. 77 | 78 | A future version of this sample will allow the user to provide this information as a runtime parameter for each and every import job, pull requests welcome! 79 | 80 | 7. Run Terraform to create all your resources in OCI 81 | 82 | `terraform init` 83 | 84 | `terraform plan` 85 | 86 | `terraform apply` 87 | 88 | 8. This step creates all the resources in OCI , including the setup of a VCN, an API Gateway, uploading the Oracle Cloud Functions and creating a OCI Vault to store the Fusion ERP password. The Terraform script does not create the OCI Vault Secret as this is currently not possible using Terraform. The Terraform script will however create a dummy ERP password within the vault and you will need to update this with the real password for your Oracle Fusion ERP system. 89 | 90 | 9. Update the *erppassword* secret within the Oracle Vault 91 | 92 | - Log In to OCI console 93 | 94 | - Navigate to the vault (**Menu Security/Vault/VaultName**) 95 | 96 | - Within resources select **Secrets** 97 | 98 | - Select the **erp_password** Secret 99 | 100 | - Create a new secret version and enter your ERP password here 101 | 102 | ![Secret](images/secret.png) 103 | 104 | - Once the secret has been created, make a note of the secret OCID 105 | 106 | 10. Once the Terraform script has run you should receive an email asking to confirm the notification subscriptions. 107 | 108 | ## Running the sample 109 | 110 | The current sample imports invoices into Oracle Fusion. 111 | 112 | 1. Examine the sample JSON file, this is a simplified JSON representation of the invoice and invoice lines. Within this file ensure 113 | 1. The "`invoice_id`" and "invoice number" are unique 114 | 2. The `supplierNumber` exists in your Fusion system 115 | 3. Make any other modifications, like adding line items etc 116 | 2. Upload the JSON file into the **JSON Incoming Bucket** on OCI cloud Storage. 117 | 3. Within a minute you should see that the file has disappeared and will reappear in the **ZIP Incoming Bucket,** this means the transform process has completed and a ERP SaaS ZIP file has been created. 118 | 4. Within a minute you should see the file has disappeared and is now in the "Processing" storage bucket/ The filename will also have a JOBID appended to it. This means the *Load* function has executed and has loaded the file into Oracle Fusion ERP 119 | 5. Within a couple of minutes, it depends how busy Fusion ERP is, you should then see the ZIP file be moved from the "Processing" bucket to either the "Success" or "Failure" bucket. this has occurred because Oracle Fusion SaaS has imported the data and the function examined the payload and determined if the data was "processed" correctly. This does not mean the data was *loaded*, there could have been bad data, duplicate rows or invalid business unit. A future enhancement would be to examine the status of the file load by processing the ESS job log file. 120 | 6. Go into Oracle Fusion, Procurement, Invoices and query your newly serverless loaded invoice. 121 | 122 | ## Troubleshooting 123 | 124 | - If things dont work, here are some [troubleshooting tips for Oracle Cloud Functions](https://docs.cloud.oracle.com/en-us/iaas/Content/Functions/Tasks/functionstroubleshooting.htm) you can try. 125 | 126 | - The Oracle Cloud Functions are configured to emit logging info using standard system logging, this can be useful when debugging the functions. This logging can be either retrieved in OCI Logging or you can use a 3rd party remote syslogurl logging service. OCI Logging is installed/configured by default , if you want to use a 3rd party system like [Papertrail](https://papertrailapp.com/) then setup the remote logging using the following command. 127 | 128 | `fn update app Serverless_Integration --syslog-url ` 129 | 130 | - For more information see this [blog article](https://blogs.oracle.com/developers/simple-serverless-logging-for-oracle-functions) written by the Oracle OCI development organisation where they explain how to setup logging for Oracle Cloud Functions. 131 | 132 | ## Enhancing the sample 133 | 134 | Adding support for new ERP Objects 135 | 136 | - The current transform cloud function focuses on the invoice, and Invoice lines, object. The `erp-transform-file` uses a template CSV file where elements to be replaced are marked with $ and are replaced by the Python script. 137 | - To add a new object you would need to : 138 | - a) Create your custom JSON file format for the data you are uploading into Oracle Fusion ERP 139 | - b) Create your own custom transform cloud function. This cloud function would be similar to the `erp-transform-file.py ` file. You can use the existing `erp-transform-file` Python code as a template demonstrating how to parse the file, extract out the JSON elements, construct the ERP Specific CSV file, ZIP the resulting files and finally interact with OCI services such as storage buckets and notifications. 140 | - c) For each new ERP object you will also need also provide the **job name(s)** and **param list** (parameters in Terraform `fusion_metadata` object within the `general_config.auto.tfvars`. This information can be obtained by executing a data load manually in Oracle Fusion ERP and then seeing the resulting process details in the schedule processes section (aka ESS) 141 | 142 | Supporting multiple objects using multiple instances of the code 143 | 144 | - This sample currently deals with a single data file and destination object (i.e. invoices and invoice lines). To support multiple objects you will need to deploy the sample multiple times with different bucket names, configuration files etc. 145 | 146 | Supporting multiple objects with a single code base 147 | 148 | - An interesting enhancement would be to allow the users the ability to create multiple "*profiles*" for different incoming data files, the discriminator could be based on the file prefix (e.g. invoices_batch10.json). When a file is uploaded into the JSON OCI Bucket, a router function could look up the appropriate transform function by using the prefix name as a key. Therefore instead of a function called `erp-transform-file` we would have multiple Oracle Cloud Functions for each object type, i.e. one called *erp-transform-invoices, erp-transform-gl* etc. These Oracle Cloud Functions could still place their resulting ZIP files into a single OCI ZIP bucket and then again a single `erp-file-load` function could determine the right *job names, param lists* based on the file prefix. 149 | 150 | Supporting large files 151 | 152 | - The transform cloud function reads the entire JSON file into memory and generates the CSV file in Oracle Cloud Functions temporary storage. Whilst this approach is efficient it does mean there is a limit to the amount of data the cloud function can process. Currently the max amount of memory an Oracle Cloud Function can be allocated is 1Gb and disk maximums of 256Mb in */tmp* also apply. This means the max size of the zip file that can be created is approx. 256Mb before being transferred to OCI Object Storage Cloud. If you need to produce zip files larger than 256Mb then either split the load into smaller chunks or implement a streaming approach in the various Oracle Cloud Functions in this sample. 153 | 154 | - See [Oracle Cloud Functions accessing filesystem documentation](https://docs.cloud.oracle.com/en-us/iaas/Content/Functions/Tasks/functionsaccessinglocalfilesystem.htm) link for more details on filesystem size limits 155 | 156 | ## Security 157 | 158 | Oracle takes security seriously and has a dedicated response team for [reporting security vulnerabilities](./SECURITY.md) and to answer any security and vulnerability related questions. 159 | 160 | ## Contributing 161 | 162 | We welcome all contributions to this sample and have a [contribution guide](./CONTRIBUTING.md) for you to follow if you'd like to contribute. 163 | 164 | ## Help 165 | 166 | If you need help with this sample, please log an issue within this repository and the code owners will help out where we can. 167 | 168 | ## License 169 | 170 | Copyright (c) 2021, 2022 Oracle and/or its affiliates. 171 | 172 | Released under the Universal Permissive License v1.0 as shown at 173 | . 174 | -------------------------------------------------------------------------------- /THIRD_PARTY_LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | LICENSES FOR THIRD-PARTY COMPONENTS 3 | 4 | =============================================================================== 5 | 6 | The following sections contain licensing information for libraries that we have 7 | included with the source and/or components used to test. We are thankful to all 8 | individuals that have created these. The following software may be included 9 | in this project: 10 | 11 | 12 | 13 | =============================================================================== 14 | 15 | fdk-python 16 | https://github.com/fnproject/fdk-python 17 | Licence : Apache License, Version 2.0 18 | ------------------------------------------------------------------------------------- 19 | oci-python-sdk 20 | https://github.com/oracle/oci-python-sdk 21 | License: Universal Permissive License (UPL), Version 1.0 22 | ------------------------------------------------------------------------------------- 23 | terraform-provider-oci 24 | https://github.com/terraform-providers/terraform-provider-oci 25 | Licence: Mozilla Public License Version 2.0 26 | ------------------------------------------------------------------------------------- 27 | terraform 28 | https://github.com/hashicorp/terraform 29 | Licence: Mozilla Public License v2.0 30 | ------------------------------------------------------------------------------------- 31 | terraform-provider-random v3.0 32 | https://github.com/hashicorp/terraform-provider-random 33 | Licence: Mozilla Public License Version 2.0 34 | ------------------------------------------------------------------------------------- 35 | terraform-provider-null v3.0 36 | https://github.com/hashicorp/terraform-provider-null 37 | Licence: Mozilla Public License Version 2.0 38 | ------------------------------------------------------------------------------------- 39 | python requests 40 | https://github.com/psf/requests 41 | Licence: Apache License 2.0 42 | Copyright 2019 Kenneth Reitz 43 | ------------------------------------------------------------------------------------- 44 | 3rd Party Licenses 45 | 46 | oci-python-sdk 47 | 48 | Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. 49 | 50 | This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 or Apache License 2.0. See below for license terms. You may choose either license. 51 | ____________________________ 52 | The Universal Permissive License (UPL), Version 1.0 53 | Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. 54 | 55 | Subject to the condition set forth below, permission is hereby granted to any person obtaining a copy of this software, associated documentation and/or data (collectively the "Software"), free of charge and under any and all copyright rights in the Software, and any and all patent rights owned or freely licensable by each licensor hereunder covering either (i) the unmodified Software as contributed to or provided by such licensor, or (ii) the Larger Works (as defined below), to deal in both 56 | 57 | (a) the Software, and 58 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if one is included with the Software (each a "Larger Work" to which the Software is contributed by such licensors), 59 | 60 | without restriction, including without limitation the rights to copy, create derivative works of, display, perform, and distribute the Software and make, use, sell, offer for sale, import, export, have made, and have sold the Software and the Larger Work(s), and to sublicense the foregoing rights on either these or other terms. 61 | 62 | This license is subject to the following condition: 63 | 64 | The above copyright notice and either this complete permission notice or at a minimum a reference to the UPL must be included in all copies or substantial portions of the Software. 65 | 66 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 67 | 68 | 69 | 70 | 71 | 72 | 73 | Apache License 74 | Version 2.0, January 2004 75 | http://www.apache.org/licenses/ 76 | 77 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 78 | 79 | 1. Definitions. 80 | 81 | "License" shall mean the terms and conditions for use, reproduction, 82 | and distribution as defined by Sections 1 through 9 of this document. 83 | 84 | "Licensor" shall mean the copyright owner or entity authorized by 85 | the copyright owner that is granting the License. 86 | 87 | "Legal Entity" shall mean the union of the acting entity and all 88 | other entities that control, are controlled by, or are under common 89 | control with that entity. For the purposes of this definition, 90 | "control" means (i) the power, direct or indirect, to cause the 91 | direction or management of such entity, whether by contract or 92 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 93 | outstanding shares, or (iii) beneficial ownership of such entity. 94 | 95 | "You" (or "Your") shall mean an individual or Legal Entity 96 | exercising permissions granted by this License. 97 | 98 | "Source" form shall mean the preferred form for making modifications, 99 | including but not limited to software source code, documentation 100 | source, and configuration files. 101 | 102 | "Object" form shall mean any form resulting from mechanical 103 | transformation or translation of a Source form, including but 104 | not limited to compiled object code, generated documentation, 105 | and conversions to other media types. 106 | 107 | "Work" shall mean the work of authorship, whether in Source or 108 | Object form, made available under the License, as indicated by a 109 | copyright notice that is included in or attached to the work 110 | (an example is provided in the Appendix below). 111 | 112 | "Derivative Works" shall mean any work, whether in Source or Object 113 | form, that is based on (or derived from) the Work and for which the 114 | editorial revisions, annotations, elaborations, or other modifications 115 | represent, as a whole, an original work of authorship. For the purposes 116 | of this License, Derivative Works shall not include works that remain 117 | separable from, or merely link (or bind by name) to the interfaces of, 118 | the Work and Derivative Works thereof. 119 | 120 | "Contribution" shall mean any work of authorship, including 121 | the original version of the Work and any modifications or additions 122 | to that Work or Derivative Works thereof, that is intentionally 123 | submitted to Licensor for inclusion in the Work by the copyright owner 124 | or by an individual or Legal Entity authorized to submit on behalf of 125 | the copyright owner. For the purposes of this definition, "submitted" 126 | means any form of electronic, verbal, or written communication sent 127 | to the Licensor or its representatives, including but not limited to 128 | communication on electronic mailing lists, source code control systems, 129 | and issue tracking systems that are managed by, or on behalf of, the 130 | Licensor for the purpose of discussing and improving the Work, but 131 | excluding communication that is conspicuously marked or otherwise 132 | designated in writing by the copyright owner as "Not a Contribution." 133 | 134 | "Contributor" shall mean Licensor and any individual or Legal Entity 135 | on behalf of whom a Contribution has been received by Licensor and 136 | subsequently incorporated within the Work. 137 | 138 | 2. Grant of Copyright License. Subject to the terms and conditions of 139 | this License, each Contributor hereby grants to You a perpetual, 140 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 141 | copyright license to reproduce, prepare Derivative Works of, 142 | publicly display, publicly perform, sublicense, and distribute the 143 | Work and such Derivative Works in Source or Object form. 144 | 145 | 3. Grant of Patent License. Subject to the terms and conditions of 146 | this License, each Contributor hereby grants to You a perpetual, 147 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 148 | (except as stated in this section) patent license to make, have made, 149 | use, offer to sell, sell, import, and otherwise transfer the Work, 150 | where such license applies only to those patent claims licensable 151 | by such Contributor that are necessarily infringed by their 152 | Contribution(s) alone or by combination of their Contribution(s) 153 | with the Work to which such Contribution(s) was submitted. If You 154 | institute patent litigation against any entity (including a 155 | cross-claim or counterclaim in a lawsuit) alleging that the Work 156 | or a Contribution incorporated within the Work constitutes direct 157 | or contributory patent infringement, then any patent licenses 158 | granted to You under this License for that Work shall terminate 159 | as of the date such litigation is filed. 160 | 161 | 4. Redistribution. You may reproduce and distribute copies of the 162 | Work or Derivative Works thereof in any medium, with or without 163 | modifications, and in Source or Object form, provided that You 164 | meet the following conditions: 165 | 166 | (a) You must give any other recipients of the Work or 167 | Derivative Works a copy of this License; and 168 | 169 | (b) You must cause any modified files to carry prominent notices 170 | stating that You changed the files; and 171 | 172 | (c) You must retain, in the Source form of any Derivative Works 173 | that You distribute, all copyright, patent, trademark, and 174 | attribution notices from the Source form of the Work, 175 | excluding those notices that do not pertain to any part of 176 | the Derivative Works; and 177 | 178 | (d) If the Work includes a "NOTICE" text file as part of its 179 | distribution, then any Derivative Works that You distribute must 180 | include a readable copy of the attribution notices contained 181 | within such NOTICE file, excluding those notices that do not 182 | pertain to any part of the Derivative Works, in at least one 183 | of the following places: within a NOTICE text file distributed 184 | as part of the Derivative Works; within the Source form or 185 | documentation, if provided along with the Derivative Works; or, 186 | within a display generated by the Derivative Works, if and 187 | wherever such third-party notices normally appear. The contents 188 | of the NOTICE file are for informational purposes only and 189 | do not modify the License. You may add Your own attribution 190 | notices within Derivative Works that You distribute, alongside 191 | or as an addendum to the NOTICE text from the Work, provided 192 | that such additional attribution notices cannot be construed 193 | as modifying the License. 194 | 195 | You may add Your own copyright statement to Your modifications and 196 | may provide additional or different license terms and conditions 197 | for use, reproduction, or distribution of Your modifications, or 198 | for any such Derivative Works as a whole, provided Your use, 199 | reproduction, and distribution of the Work otherwise complies with 200 | the conditions stated in this License. 201 | 202 | 5. Submission of Contributions. Unless You explicitly state otherwise, 203 | any Contribution intentionally submitted for inclusion in the Work 204 | by You to the Licensor shall be under the terms and conditions of 205 | this License, without any additional terms or conditions. 206 | Notwithstanding the above, nothing herein shall supersede or modify 207 | the terms of any separate license agreement you may have executed 208 | with Licensor regarding such Contributions. 209 | 210 | 6. Trademarks. This License does not grant permission to use the trade 211 | names, trademarks, service marks, or product names of the Licensor, 212 | except as required for reasonable and customary use in describing the 213 | origin of the Work and reproducing the content of the NOTICE file. 214 | 215 | 7. Disclaimer of Warranty. Unless required by applicable law or 216 | agreed to in writing, Licensor provides the Work (and each 217 | Contributor provides its Contributions) on an "AS IS" BASIS, 218 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 219 | implied, including, without limitation, any warranties or conditions 220 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 221 | PARTICULAR PURPOSE. You are solely responsible for determining the 222 | appropriateness of using or redistributing the Work and assume any 223 | risks associated with Your exercise of permissions under this License. 224 | 225 | 8. Limitation of Liability. In no event and under no legal theory, 226 | whether in tort (including negligence), contract, or otherwise, 227 | unless required by applicable law (such as deliberate and grossly 228 | negligent acts) or agreed to in writing, shall any Contributor be 229 | liable to You for damages, including any direct, indirect, special, 230 | incidental, or consequential damages of any character arising as a 231 | result of this License or out of the use or inability to use the 232 | Work (including but not limited to damages for loss of goodwill, 233 | work stoppage, computer failure or malfunction, or any and all 234 | other commercial damages or losses), even if such Contributor 235 | has been advised of the possibility of such damages. 236 | 237 | 9. Accepting Warranty or Additional Liability. While redistributing 238 | the Work or Derivative Works thereof, You may choose to offer, 239 | and charge a fee for, acceptance of support, warranty, indemnity, 240 | or other liability obligations and/or rights consistent with this 241 | License. However, in accepting such obligations, You may act only 242 | on Your own behalf and on Your sole responsibility, not on behalf 243 | of any other Contributor, and only if You agree to indemnify, 244 | defend, and hold each Contributor harmless for any liability 245 | incurred by, or claims asserted against, such Contributor by reason 246 | of your accepting any such warranty or additional liability. 247 | 248 | END OF TERMS AND CONDITIONS 249 | 250 | APPENDIX: How to apply the Apache License to your work. 251 | 252 | To apply the Apache License to your work, attach the following 253 | boilerplate notice, with the fields enclosed by brackets "{}" 254 | replaced with your own identifying information. (Don't include 255 | the brackets!) The text should be enclosed in the appropriate 256 | comment syntax for the file format. We also recommend that a 257 | file or class name and description of purpose be included on the 258 | same "printed page" as the copyright notice for easier 259 | identification within third-party archives. 260 | 261 | Copyright {yyyy} {name of copyright owner} 262 | 263 | Licensed under the Apache License, Version 2.0 (the "License"); 264 | you may not use this file except in compliance with the License. 265 | You may obtain a copy of the License at 266 | 267 | http://www.apache.org/licenses/LICENSE-2.0 268 | 269 | Unless required by applicable law or agreed to in writing, software 270 | distributed under the License is distributed on an "AS IS" BASIS, 271 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 272 | See the License for the specific language governing permissions and 273 | limitations under the License. 274 | 275 | 276 | 277 | Mozilla Public License, version 2.0 278 | 279 | 1. Definitions 280 | 281 | 1.1. “Contributor” 282 | 283 | means each individual or legal entity that creates, contributes to the 284 | creation of, or owns Covered Software. 285 | 286 | 1.2. “Contributor Version” 287 | 288 | means the combination of the Contributions of others (if any) used by a 289 | Contributor and that particular Contributor’s Contribution. 290 | 291 | 1.3. “Contribution” 292 | 293 | means Covered Software of a particular Contributor. 294 | 295 | 1.4. “Covered Software” 296 | 297 | means Source Code Form to which the initial Contributor has attached the 298 | notice in Exhibit A, the Executable Form of such Source Code Form, and 299 | Modifications of such Source Code Form, in each case including portions 300 | thereof. 301 | 302 | 1.5. “Incompatible With Secondary Licenses” 303 | means 304 | 305 | a. that the initial Contributor has attached the notice described in 306 | Exhibit B to the Covered Software; or 307 | 308 | b. that the Covered Software was made available under the terms of version 309 | 1.1 or earlier of the License, but not also under the terms of a 310 | Secondary License. 311 | 312 | 1.6. “Executable Form” 313 | 314 | means any form of the work other than Source Code Form. 315 | 316 | 1.7. “Larger Work” 317 | 318 | means a work that combines Covered Software with other material, in a separate 319 | file or files, that is not Covered Software. 320 | 321 | 1.8. “License” 322 | 323 | means this document. 324 | 325 | 1.9. “Licensable” 326 | 327 | means having the right to grant, to the maximum extent possible, whether at the 328 | time of the initial grant or subsequently, any and all of the rights conveyed by 329 | this License. 330 | 331 | 1.10. “Modifications” 332 | 333 | means any of the following: 334 | 335 | a. any file in Source Code Form that results from an addition to, deletion 336 | from, or modification of the contents of Covered Software; or 337 | 338 | b. any new file in Source Code Form that contains any Covered Software. 339 | 340 | 1.11. “Patent Claims” of a Contributor 341 | 342 | means any patent claim(s), including without limitation, method, process, 343 | and apparatus claims, in any patent Licensable by such Contributor that 344 | would be infringed, but for the grant of the License, by the making, 345 | using, selling, offering for sale, having made, import, or transfer of 346 | either its Contributions or its Contributor Version. 347 | 348 | 1.12. “Secondary License” 349 | 350 | means either the GNU General Public License, Version 2.0, the GNU Lesser 351 | General Public License, Version 2.1, the GNU Affero General Public 352 | License, Version 3.0, or any later versions of those licenses. 353 | 354 | 1.13. “Source Code Form” 355 | 356 | means the form of the work preferred for making modifications. 357 | 358 | 1.14. “You” (or “Your”) 359 | 360 | means an individual or a legal entity exercising rights under this 361 | License. For legal entities, “You” includes any entity that controls, is 362 | controlled by, or is under common control with You. For purposes of this 363 | definition, “control” means (a) the power, direct or indirect, to cause 364 | the direction or management of such entity, whether by contract or 365 | otherwise, or (b) ownership of more than fifty percent (50%) of the 366 | outstanding shares or beneficial ownership of such entity. 367 | 368 | 369 | 2. License Grants and Conditions 370 | 371 | 2.1. Grants 372 | 373 | Each Contributor hereby grants You a world-wide, royalty-free, 374 | non-exclusive license: 375 | 376 | a. under intellectual property rights (other than patent or trademark) 377 | Licensable by such Contributor to use, reproduce, make available, 378 | modify, display, perform, distribute, and otherwise exploit its 379 | Contributions, either on an unmodified basis, with Modifications, or as 380 | part of a Larger Work; and 381 | 382 | b. under Patent Claims of such Contributor to make, use, sell, offer for 383 | sale, have made, import, and otherwise transfer either its Contributions 384 | or its Contributor Version. 385 | 386 | 2.2. Effective Date 387 | 388 | The licenses granted in Section 2.1 with respect to any Contribution become 389 | effective for each Contribution on the date the Contributor first distributes 390 | such Contribution. 391 | 392 | 2.3. Limitations on Grant Scope 393 | 394 | The licenses granted in this Section 2 are the only rights granted under this 395 | License. No additional rights or licenses will be implied from the distribution 396 | or licensing of Covered Software under this License. Notwithstanding Section 397 | 2.1(b) above, no patent license is granted by a Contributor: 398 | 399 | a. for any code that a Contributor has removed from Covered Software; or 400 | 401 | b. for infringements caused by: (i) Your and any other third party’s 402 | modifications of Covered Software, or (ii) the combination of its 403 | Contributions with other software (except as part of its Contributor 404 | Version); or 405 | 406 | c. under Patent Claims infringed by Covered Software in the absence of its 407 | Contributions. 408 | 409 | This License does not grant any rights in the trademarks, service marks, or 410 | logos of any Contributor (except as may be necessary to comply with the 411 | notice requirements in Section 3.4). 412 | 413 | 2.4. Subsequent Licenses 414 | 415 | No Contributor makes additional grants as a result of Your choice to 416 | distribute the Covered Software under a subsequent version of this License 417 | (see Section 10.2) or under the terms of a Secondary License (if permitted 418 | under the terms of Section 3.3). 419 | 420 | 2.5. Representation 421 | 422 | Each Contributor represents that the Contributor believes its Contributions 423 | are its original creation(s) or it has sufficient rights to grant the 424 | rights to its Contributions conveyed by this License. 425 | 426 | 2.6. Fair Use 427 | 428 | This License is not intended to limit any rights You have under applicable 429 | copyright doctrines of fair use, fair dealing, or other equivalents. 430 | 431 | 2.7. Conditions 432 | 433 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in 434 | Section 2.1. 435 | 436 | 437 | 3. Responsibilities 438 | 439 | 3.1. Distribution of Source Form 440 | 441 | All distribution of Covered Software in Source Code Form, including any 442 | Modifications that You create or to which You contribute, must be under the 443 | terms of this License. You must inform recipients that the Source Code Form 444 | of the Covered Software is governed by the terms of this License, and how 445 | they can obtain a copy of this License. You may not attempt to alter or 446 | restrict the recipients’ rights in the Source Code Form. 447 | 448 | 3.2. Distribution of Executable Form 449 | 450 | If You distribute Covered Software in Executable Form then: 451 | 452 | a. such Covered Software must also be made available in Source Code Form, 453 | as described in Section 3.1, and You must inform recipients of the 454 | Executable Form how they can obtain a copy of such Source Code Form by 455 | reasonable means in a timely manner, at a charge no more than the cost 456 | of distribution to the recipient; and 457 | 458 | b. You may distribute such Executable Form under the terms of this License, 459 | or sublicense it under different terms, provided that the license for 460 | the Executable Form does not attempt to limit or alter the recipients’ 461 | rights in the Source Code Form under this License. 462 | 463 | 3.3. Distribution of a Larger Work 464 | 465 | You may create and distribute a Larger Work under terms of Your choice, 466 | provided that You also comply with the requirements of this License for the 467 | Covered Software. If the Larger Work is a combination of Covered Software 468 | with a work governed by one or more Secondary Licenses, and the Covered 469 | Software is not Incompatible With Secondary Licenses, this License permits 470 | You to additionally distribute such Covered Software under the terms of 471 | such Secondary License(s), so that the recipient of the Larger Work may, at 472 | their option, further distribute the Covered Software under the terms of 473 | either this License or such Secondary License(s). 474 | 475 | 3.4. Notices 476 | 477 | You may not remove or alter the substance of any license notices (including 478 | copyright notices, patent notices, disclaimers of warranty, or limitations 479 | of liability) contained within the Source Code Form of the Covered 480 | Software, except that You may alter any license notices to the extent 481 | required to remedy known factual inaccuracies. 482 | 483 | 3.5. Application of Additional Terms 484 | 485 | You may choose to offer, and to charge a fee for, warranty, support, 486 | indemnity or liability obligations to one or more recipients of Covered 487 | Software. However, You may do so only on Your own behalf, and not on behalf 488 | of any Contributor. You must make it absolutely clear that any such 489 | warranty, support, indemnity, or liability obligation is offered by You 490 | alone, and You hereby agree to indemnify every Contributor for any 491 | liability incurred by such Contributor as a result of warranty, support, 492 | indemnity or liability terms You offer. You may include additional 493 | disclaimers of warranty and limitations of liability specific to any 494 | jurisdiction. 495 | 496 | 4. Inability to Comply Due to Statute or Regulation 497 | 498 | If it is impossible for You to comply with any of the terms of this License 499 | with respect to some or all of the Covered Software due to statute, judicial 500 | order, or regulation then You must: (a) comply with the terms of this License 501 | to the maximum extent possible; and (b) describe the limitations and the code 502 | they affect. Such description must be placed in a text file included with all 503 | distributions of the Covered Software under this License. Except to the 504 | extent prohibited by statute or regulation, such description must be 505 | sufficiently detailed for a recipient of ordinary skill to be able to 506 | understand it. 507 | 508 | 5. Termination 509 | 510 | 5.1. The rights granted under this License will terminate automatically if You 511 | fail to comply with any of its terms. However, if You become compliant, 512 | then the rights granted under this License from a particular Contributor 513 | are reinstated (a) provisionally, unless and until such Contributor 514 | explicitly and finally terminates Your grants, and (b) on an ongoing basis, 515 | if such Contributor fails to notify You of the non-compliance by some 516 | reasonable means prior to 60 days after You have come back into compliance. 517 | Moreover, Your grants from a particular Contributor are reinstated on an 518 | ongoing basis if such Contributor notifies You of the non-compliance by 519 | some reasonable means, this is the first time You have received notice of 520 | non-compliance with this License from such Contributor, and You become 521 | compliant prior to 30 days after Your receipt of the notice. 522 | 523 | 5.2. If You initiate litigation against any entity by asserting a patent 524 | infringement claim (excluding declaratory judgment actions, counter-claims, 525 | and cross-claims) alleging that a Contributor Version directly or 526 | indirectly infringes any patent, then the rights granted to You by any and 527 | all Contributors for the Covered Software under Section 2.1 of this License 528 | shall terminate. 529 | 530 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user 531 | license agreements (excluding distributors and resellers) which have been 532 | validly granted by You or Your distributors under this License prior to 533 | termination shall survive termination. 534 | 535 | 6. Disclaimer of Warranty 536 | 537 | Covered Software is provided under this License on an “as is” basis, without 538 | warranty of any kind, either expressed, implied, or statutory, including, 539 | without limitation, warranties that the Covered Software is free of defects, 540 | merchantable, fit for a particular purpose or non-infringing. The entire 541 | risk as to the quality and performance of the Covered Software is with You. 542 | Should any Covered Software prove defective in any respect, You (not any 543 | Contributor) assume the cost of any necessary servicing, repair, or 544 | correction. This disclaimer of warranty constitutes an essential part of this 545 | License. No use of any Covered Software is authorized under this License 546 | except under this disclaimer. 547 | 548 | 7. Limitation of Liability 549 | 550 | Under no circumstances and under no legal theory, whether tort (including 551 | negligence), contract, or otherwise, shall any Contributor, or anyone who 552 | distributes Covered Software as permitted above, be liable to You for any 553 | direct, indirect, special, incidental, or consequential damages of any 554 | character including, without limitation, damages for lost profits, loss of 555 | goodwill, work stoppage, computer failure or malfunction, or any and all 556 | other commercial damages or losses, even if such party shall have been 557 | informed of the possibility of such damages. This limitation of liability 558 | shall not apply to liability for death or personal injury resulting from such 559 | party’s negligence to the extent applicable law prohibits such limitation. 560 | Some jurisdictions do not allow the exclusion or limitation of incidental or 561 | consequential damages, so this exclusion and limitation may not apply to You. 562 | 563 | 8. Litigation 564 | 565 | Any litigation relating to this License may be brought only in the courts of 566 | a jurisdiction where the defendant maintains its principal place of business 567 | and such litigation shall be governed by laws of that jurisdiction, without 568 | reference to its conflict-of-law provisions. Nothing in this Section shall 569 | prevent a party’s ability to bring cross-claims or counter-claims. 570 | 571 | 9. Miscellaneous 572 | 573 | This License represents the complete agreement concerning the subject matter 574 | hereof. If any provision of this License is held to be unenforceable, such 575 | provision shall be reformed only to the extent necessary to make it 576 | enforceable. Any law or regulation which provides that the language of a 577 | contract shall be construed against the drafter shall not be used to construe 578 | this License against a Contributor. 579 | 580 | 581 | 10. Versions of the License 582 | 583 | 10.1. New Versions 584 | 585 | Mozilla Foundation is the license steward. Except as provided in Section 586 | 10.3, no one other than the license steward has the right to modify or 587 | publish new versions of this License. Each version will be given a 588 | distinguishing version number. 589 | 590 | 10.2. Effect of New Versions 591 | 592 | You may distribute the Covered Software under the terms of the version of 593 | the License under which You originally received the Covered Software, or 594 | under the terms of any subsequent version published by the license 595 | steward. 596 | 597 | 10.3. Modified Versions 598 | 599 | If you create software not governed by this License, and you want to 600 | create a new license for such software, you may create and use a modified 601 | version of this License if you rename the license and remove any 602 | references to the name of the license steward (except to note that such 603 | modified license differs from this License). 604 | 605 | 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses 606 | If You choose to distribute Source Code Form that is Incompatible With 607 | Secondary Licenses under the terms of this version of the License, the 608 | notice described in Exhibit B of this License must be attached. 609 | 610 | Exhibit A - Source Code Form License Notice 611 | 612 | This Source Code Form is subject to the 613 | terms of the Mozilla Public License, v. 614 | 2.0. If a copy of the MPL was not 615 | distributed with this file, You can 616 | obtain one at 617 | http://mozilla.org/MPL/2.0/. 618 | 619 | If it is not possible or desirable to put the notice in a particular file, then 620 | You may include the notice in a location (such as a LICENSE file in a relevant 621 | directory) where a recipient would be likely to look for such a notice. 622 | 623 | You may add additional accurate notices of copyright ownership. 624 | 625 | Exhibit B - “Incompatible With Secondary Licenses” Notice 626 | 627 | This Source Code Form is “Incompatible 628 | With Secondary Licenses”, as defined by 629 | the Mozilla Public License, v. 2.0. 630 | 631 | 632 | 633 | =============================================================================== 634 | ## FOURTH PARTY INFORMATION: 635 | 636 | fdk@0.1.21 depends on the following 637 | technologies/licenses. A copy of each license is included accordingly. 638 | 639 | - httptools@0.1.1 (MIT) 640 | - iso8601@0.1.12 (MIT) 641 | - pbr@5.4.5 (Apache-2.0) 642 | - pytest@5.4.3 (MIT) 643 | - attrs@20.3.0 (MIT) 644 | - more-itertools@8.6.0 (MIT) 645 | - packaging@20.9 (Apache-2.0 OR BSD-3-Clause) 646 | - pyparsing@2.4.7 (MIT) 647 | - pluggy@0.13.1 (MIT) 648 | - py@1.10.0 (MIT) 649 | - wcwidth@0.2.5 (MIT) 650 | - pytest-asyncio@0.12.0 (Apache-2.0) 651 | 652 | 653 | =============================================================================== 654 | ### httptools@0.1.1 (MIT) 655 | 656 | The MIT License 657 | Copyright (c) 2015 MagicStack Inc. http://magic.io 658 | 659 | 660 | 661 | =============================================================================== 662 | ### iso8601@0.1.12 (MIT) 663 | MIT License Copyright (c) 664 | 665 | =============================================================================== 666 | ### pbr@5.4.5 (Apache-2.0) 667 | 668 | 669 | =============================================================================== 670 | ### pytest@5.4.3 (MIT) 671 | The MIT License (MIT) 672 | 673 | 674 | 675 | 676 | =============================================================================== 677 | ### attrs@20.3.0 (MIT) 678 | 679 | The MIT License (MIT) 680 | Copyright (c) 2015 Hynek Schlawack 681 | 682 | 683 | =============================================================================== 684 | ### more-itertools@8.6.0 (MIT) 685 | 686 | Copyright (c) 2012 Erik Rose 687 | 688 | 689 | 690 | =============================================================================== 691 | ### packaging@20.9 (Apache-2.0 OR BSD-3-Clause) 692 | 693 | This software is made available under the terms of *either* of the licenses 694 | found in LICENSE.APACHE or LICENSE.BSD. Contributions to this software is made 695 | under the terms of *both* these licenses. 696 | 697 | 698 | =============================================================================== 699 | ### pyparsing@2.4.7 (MIT) 700 | 701 | 702 | =============================================================================== 703 | ### pluggy@0.13.1 (MIT) 704 | 705 | The MIT License (MIT) 706 | Copyright (c) 2015 holger krekel (rather uses bitbucket/hpk42) 707 | 708 | =============================================================================== 709 | ### py@1.10.0 (MIT) 710 | 711 | 712 | =============================================================================== 713 | ### wcwidth@0.2.5 (MIT) 714 | 715 | The MIT License (MIT) 716 | 717 | Copyright (c) 2014 Jeff Quast 718 | 719 | 720 | 721 | =============================================================================== 722 | ### pytest-asyncio@0.12.0 (Apache-2.0) 723 | 724 | 725 | 726 | =============================================================================== 727 | ## oci@2.24.0 (Apache-2.0 OR UPL-1.0) 728 | 729 | =============================================================================== 730 | ## FOURTH PARTY INFORMATION: 731 | 732 | oci@2.24.0 depends on the following 733 | technologies/licenses. A copy of each license is included accordingly. 734 | 735 | - certifi@2020.12.5 (MPL-2.0) 736 | - configparser@4.0.2 (MIT) 737 | - cryptography@2.8 (Apache-2.0 OR BSD-3-Clause) 738 | - cffi@1.14.4 (MIT) 739 | - pycparser@2.20 (BSD-3-Clause) 740 | - six@1.15.0 (MIT) 741 | - pyOpenSSL@19.1.0 (Apache-2.0) 742 | - pycparser@2.20 (BSD-3-Clause) 743 | - python-dateutil@2.8.1 (BSD-3-Clause OR Apache-2.0) 744 | - pytz@2021.1 (MIT) 745 | 746 | 747 | =============================================================================== 748 | ### certifi@2020.12.5 (MPL-2.0) 749 | 750 | This packge contains a modified version of ca-bundle.crt: 751 | 752 | ca-bundle.crt -- Bundle of CA Root Certificates 753 | 754 | Certificate data from Mozilla as of: Thu Nov 3 19:04:19 2011# 755 | This is a bundle of X.509 certificates of public Certificate Authorities 756 | (CA). These were automatically extracted from Mozilla's root certificates 757 | file (certdata.txt). This file can be found in the mozilla source tree: 758 | http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1# 759 | It contains the certificates in PEM format and therefore 760 | can be directly used with curl / libcurl / php_curl, or with 761 | an Apache+mod_ssl webserver for SSL client authentication. 762 | Just configure this file as the SSLCACertificateFile.# 763 | 764 | ***** BEGIN LICENSE BLOCK ***** 765 | This Source Code Form is subject to the terms of the Mozilla Public License, 766 | v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain 767 | one at http://mozilla.org/MPL/2.0/. 768 | 769 | ***** END LICENSE BLOCK ***** 770 | @(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $ 771 | 772 | 773 | =============================================================================== 774 | ### configparser@4.0.2 (MIT) 775 | 776 | Copyright Jason R. Coombs 777 | 778 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 779 | 780 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 781 | 782 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 783 | 784 | 785 | =============================================================================== 786 | ### cryptography@2.8 (Apache-2.0 OR BSD-3-Clause) 787 | 788 | This software is made available under the terms of *either* of the licenses 789 | found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made 790 | under the terms of *both* these licenses. 791 | 792 | The code used in the OpenSSL locking callback and OS random engine is derived 793 | from CPython, and is licensed under the terms of the PSF License Agreement. 794 | 795 | 796 | =============================================================================== 797 | ### cffi@1.14.4 (MIT) 798 | 799 | 800 | Except when otherwise stated (look for LICENSE files in directories or 801 | information at the beginning of each file) all software and 802 | documentation is licensed as follows: 803 | 804 | 805 | 806 | 807 | =============================================================================== 808 | ### pycparser@2.20 (BSD-3-Clause) 809 | 810 | pycparser -- A C parser in Python 811 | 812 | Copyright (c) 2008-2017, Eli Bendersky 813 | All rights reserved. 814 | 815 | Redistribution and use in source and binary forms, with or without modification, 816 | are permitted provided that the following conditions are met: 817 | 818 | * Redistributions of source code must retain the above copyright notice, this 819 | list of conditions and the following disclaimer. 820 | * Redistributions in binary form must reproduce the above copyright notice, 821 | this list of conditions and the following disclaimer in the documentation 822 | and/or other materials provided with the distribution. 823 | * Neither the name of Eli Bendersky nor the names of its contributors may 824 | be used to endorse or promote products derived from this software without 825 | specific prior written permission. 826 | 827 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 828 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 829 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 830 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 831 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 832 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 833 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 834 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 835 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 836 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 837 | 838 | 839 | =============================================================================== 840 | ### six@1.15.0 (MIT) 841 | 842 | Copyright (c) 2010-2020 Benjamin Peterson 843 | 844 | =============================================================================== 845 | ### pyOpenSSL@19.1.0 (Apache-2.0) 846 | 847 | 848 | 849 | =============================================================================== 850 | ### pycparser@2.20 (BSD-3-Clause) 851 | 852 | pycparser -- A C parser in Python 853 | 854 | Copyright (c) 2008-2017, Eli Bendersky 855 | All rights reserved. 856 | 857 | Redistribution and use in source and binary forms, with or without modification, 858 | are permitted provided that the following conditions are met: 859 | 860 | * Redistributions of source code must retain the above copyright notice, this 861 | list of conditions and the following disclaimer. 862 | * Redistributions in binary form must reproduce the above copyright notice, 863 | this list of conditions and the following disclaimer in the documentation 864 | and/or other materials provided with the distribution. 865 | * Neither the name of Eli Bendersky nor the names of its contributors may 866 | be used to endorse or promote products derived from this software without 867 | specific prior written permission. 868 | 869 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 870 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 871 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 872 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 873 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 874 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 875 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 876 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 877 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 878 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 879 | 880 | 881 | =============================================================================== 882 | ### python-dateutil@2.8.1 (BSD-3-Clause OR Apache-2.0) 883 | 884 | Copyright 2017- Paul Ganssle 885 | Copyright 2017- dateutil contributors (see AUTHORS file) 886 | 887 | Licensed under the Apache License, Version 2.0 (the "License"); 888 | you may not use this file except in compliance with the License. 889 | You may obtain a copy of the License at 890 | 891 | http://www.apache.org/licenses/LICENSE-2.0 892 | 893 | Unless required by applicable law or agreed to in writing, software 894 | distributed under the License is distributed on an "AS IS" BASIS, 895 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 896 | See the License for the specific language governing permissions and 897 | limitations under the License. 898 | 899 | The above license applies to all contributions after 2017-12-01, as well as 900 | all contributions that have been re-licensed (see AUTHORS file for the list of 901 | contributors who have re-licensed their code). 902 | -------------------------------------------------------------------------------- 903 | dateutil - Extensions to the standard Python datetime module. 904 | 905 | Copyright (c) 2003-2011 - Gustavo Niemeyer 906 | Copyright (c) 2012-2014 - Tomi Pieviläinen 907 | Copyright (c) 2014-2016 - Yaron de Leeuw 908 | Copyright (c) 2015- - Paul Ganssle 909 | Copyright (c) 2015- - dateutil contributors (see AUTHORS file) 910 | 911 | All rights reserved. 912 | 913 | Redistribution and use in source and binary forms, with or without 914 | modification, are permitted provided that the following conditions are met: 915 | 916 | * Redistributions of source code must retain the above copyright notice, 917 | this list of conditions and the following disclaimer. 918 | * Redistributions in binary form must reproduce the above copyright notice, 919 | this list of conditions and the following disclaimer in the documentation 920 | and/or other materials provided with the distribution. 921 | * Neither the name of the copyright holder nor the names of its 922 | contributors may be used to endorse or promote products derived from 923 | this software without specific prior written permission. 924 | 925 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 926 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 927 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 928 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 929 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 930 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 931 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 932 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 933 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 934 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 935 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 936 | 937 | The above BSD License Applies to all code, even that also covered by Apache 2.0. 938 | 939 | =============================================================================== 940 | ### pytz@2021.1 (MIT) 941 | 942 | Copyright (c) 2003-2019 Stuart Bishop 943 | 944 | 945 | =============================================================================== 946 | ## requests@2.24.0 (Apache-2.0) 947 | 948 | Copyright 2019 Kenneth Reitz 949 | 950 | Licensed under the Apache License, Version 2.0 (the "License"); 951 | you may not use this file except in compliance with the License. 952 | You may obtain a copy of the License at 953 | 954 | https://www.apache.org/licenses/LICENSE-2.0 955 | 956 | Unless required by applicable law or agreed to in writing, software 957 | distributed under the License is distributed on an "AS IS" BASIS, 958 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 959 | See the License for the specific language governing permissions and 960 | limitations under the License. 961 | 962 | 963 | =============================================================================== 964 | ## FOURTH PARTY INFORMATION: 965 | 966 | requests@2.24.0 depends on the following 967 | technologies/licenses. A copy of each license is included accordingly. 968 | 969 | - certifi@2020.12.5 (MPL-2.0) 970 | - chardet@3.0.4 (LGPL-2.1) 971 | - idna@2.10 (BSD-3-Clause) 972 | - urllib3@1.25.11 (MIT) 973 | 974 | 975 | =============================================================================== 976 | ### certifi@2020.12.5 (MPL-2.0) 977 | 978 | This packge contains a modified version of ca-bundle.crt: 979 | 980 | ca-bundle.crt -- Bundle of CA Root Certificates 981 | 982 | Certificate data from Mozilla as of: Thu Nov 3 19:04:19 2011# 983 | This is a bundle of X.509 certificates of public Certificate Authorities 984 | (CA). These were automatically extracted from Mozilla's root certificates 985 | file (certdata.txt). This file can be found in the mozilla source tree: 986 | http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1# 987 | It contains the certificates in PEM format and therefore 988 | can be directly used with curl / libcurl / php_curl, or with 989 | an Apache+mod_ssl webserver for SSL client authentication. 990 | Just configure this file as the SSLCACertificateFile.# 991 | 992 | ***** BEGIN LICENSE BLOCK ***** 993 | This Source Code Form is subject to the terms of the Mozilla Public License, 994 | v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain 995 | one at http://mozilla.org/MPL/2.0/. 996 | 997 | ***** END LICENSE BLOCK ***** 998 | @(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $ 999 | 1000 | 1001 | =============================================================================== 1002 | ### chardet@3.0.4 (LGPL-2.1) 1003 | 1004 | GNU LESSER GENERAL PUBLIC LICENSE 1005 | Version 2.1, February 1999 1006 | 1007 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 1008 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 1009 | Everyone is permitted to copy and distribute verbatim copies 1010 | of this license document, but changing it is not allowed. 1011 | 1012 | [This is the first released version of the Lesser GPL. It also counts 1013 | as the successor of the GNU Library Public License, version 2, hence 1014 | the version number 2.1.] 1015 | 1016 | Preamble 1017 | 1018 | The licenses for most software are designed to take away your 1019 | freedom to share and change it. By contrast, the GNU General Public 1020 | Licenses are intended to guarantee your freedom to share and change 1021 | free software--to make sure the software is free for all its users. 1022 | 1023 | This license, the Lesser General Public License, applies to some 1024 | specially designated software packages--typically libraries--of the 1025 | Free Software Foundation and other authors who decide to use it. You 1026 | can use it too, but we suggest you first think carefully about whether 1027 | this license or the ordinary General Public License is the better 1028 | strategy to use in any particular case, based on the explanations below. 1029 | 1030 | When we speak of free software, we are referring to freedom of use, 1031 | not price. Our General Public Licenses are designed to make sure that 1032 | you have the freedom to distribute copies of free software (and charge 1033 | for this service if you wish); that you receive source code or can get 1034 | it if you want it; that you can change the software and use pieces of 1035 | it in new free programs; and that you are informed that you can do 1036 | these things. 1037 | 1038 | To protect your rights, we need to make restrictions that forbid 1039 | distributors to deny you these rights or to ask you to surrender these 1040 | rights. These restrictions translate to certain responsibilities for 1041 | you if you distribute copies of the library or if you modify it. 1042 | 1043 | For example, if you distribute copies of the library, whether gratis 1044 | or for a fee, you must give the recipients all the rights that we gave 1045 | you. You must make sure that they, too, receive or can get the source 1046 | code. If you link other code with the library, you must provide 1047 | complete object files to the recipients, so that they can relink them 1048 | with the library after making changes to the library and recompiling 1049 | it. And you must show them these terms so they know their rights. 1050 | 1051 | We protect your rights with a two-step method: (1) we copyright the 1052 | library, and (2) we offer you this license, which gives you legal 1053 | permission to copy, distribute and/or modify the library. 1054 | 1055 | To protect each distributor, we want to make it very clear that 1056 | there is no warranty for the free library. Also, if the library is 1057 | modified by someone else and passed on, the recipients should know 1058 | that what they have is not the original version, so that the original 1059 | author's reputation will not be affected by problems that might be 1060 | introduced by others. 1061 | 1062 | Finally, software patents pose a constant threat to the existence of 1063 | any free program. We wish to make sure that a company cannot 1064 | effectively restrict the users of a free program by obtaining a 1065 | restrictive license from a patent holder. Therefore, we insist that 1066 | any patent license obtained for a version of the library must be 1067 | consistent with the full freedom of use specified in this license. 1068 | 1069 | Most GNU software, including some libraries, is covered by the 1070 | ordinary GNU General Public License. This license, the GNU Lesser 1071 | General Public License, applies to certain designated libraries, and 1072 | is quite different from the ordinary General Public License. We use 1073 | this license for certain libraries in order to permit linking those 1074 | libraries into non-free programs. 1075 | 1076 | When a program is linked with a library, whether statically or using 1077 | a shared library, the combination of the two is legally speaking a 1078 | combined work, a derivative of the original library. The ordinary 1079 | General Public License therefore permits such linking only if the 1080 | entire combination fits its criteria of freedom. The Lesser General 1081 | Public License permits more lax criteria for linking other code with 1082 | the library. 1083 | 1084 | We call this license the "Lesser" General Public License because it 1085 | does Less to protect the user's freedom than the ordinary General 1086 | Public License. It also provides other free software developers Less 1087 | of an advantage over competing non-free programs. These disadvantages 1088 | are the reason we use the ordinary General Public License for many 1089 | libraries. However, the Lesser license provides advantages in certain 1090 | special circumstances. 1091 | 1092 | For example, on rare occasions, there may be a special need to 1093 | encourage the widest possible use of a certain library, so that it becomes 1094 | a de-facto standard. To achieve this, non-free programs must be 1095 | allowed to use the library. A more frequent case is that a free 1096 | library does the same job as widely used non-free libraries. In this 1097 | case, there is little to gain by limiting the free library to free 1098 | software only, so we use the Lesser General Public License. 1099 | 1100 | In other cases, permission to use a particular library in non-free 1101 | programs enables a greater number of people to use a large body of 1102 | free software. For example, permission to use the GNU C Library in 1103 | non-free programs enables many more people to use the whole GNU 1104 | operating system, as well as its variant, the GNU/Linux operating 1105 | system. 1106 | 1107 | Although the Lesser General Public License is Less protective of the 1108 | users' freedom, it does ensure that the user of a program that is 1109 | linked with the Library has the freedom and the wherewithal to run 1110 | that program using a modified version of the Library. 1111 | 1112 | The precise terms and conditions for copying, distribution and 1113 | modification follow. Pay close attention to the difference between a 1114 | "work based on the library" and a "work that uses the library". The 1115 | former contains code derived from the library, whereas the latter must 1116 | be combined with the library in order to run. 1117 | 1118 | GNU LESSER GENERAL PUBLIC LICENSE 1119 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 1120 | 1121 | 0. This License Agreement applies to any software library or other 1122 | program which contains a notice placed by the copyright holder or 1123 | other authorized party saying it may be distributed under the terms of 1124 | this Lesser General Public License (also called "this License"). 1125 | Each licensee is addressed as "you". 1126 | 1127 | A "library" means a collection of software functions and/or data 1128 | prepared so as to be conveniently linked with application programs 1129 | (which use some of those functions and data) to form executables. 1130 | 1131 | The "Library", below, refers to any such software library or work 1132 | which has been distributed under these terms. A "work based on the 1133 | Library" means either the Library or any derivative work under 1134 | copyright law: that is to say, a work containing the Library or a 1135 | portion of it, either verbatim or with modifications and/or translated 1136 | straightforwardly into another language. (Hereinafter, translation is 1137 | included without limitation in the term "modification".) 1138 | 1139 | "Source code" for a work means the preferred form of the work for 1140 | making modifications to it. For a library, complete source code means 1141 | all the source code for all modules it contains, plus any associated 1142 | interface definition files, plus the scripts used to control compilation 1143 | and installation of the library. 1144 | 1145 | Activities other than copying, distribution and modification are not 1146 | covered by this License; they are outside its scope. The act of 1147 | running a program using the Library is not restricted, and output from 1148 | such a program is covered only if its contents constitute a work based 1149 | on the Library (independent of the use of the Library in a tool for 1150 | writing it). Whether that is true depends on what the Library does 1151 | and what the program that uses the Library does. 1152 | 1153 | 1. You may copy and distribute verbatim copies of the Library's 1154 | complete source code as you receive it, in any medium, provided that 1155 | you conspicuously and appropriately publish on each copy an 1156 | appropriate copyright notice and disclaimer of warranty; keep intact 1157 | all the notices that refer to this License and to the absence of any 1158 | warranty; and distribute a copy of this License along with the 1159 | Library. 1160 | 1161 | You may charge a fee for the physical act of transferring a copy, 1162 | and you may at your option offer warranty protection in exchange for a 1163 | fee. 1164 | 1165 | 2. You may modify your copy or copies of the Library or any portion 1166 | of it, thus forming a work based on the Library, and copy and 1167 | distribute such modifications or work under the terms of Section 1 1168 | above, provided that you also meet all of these conditions: 1169 | 1170 | a) The modified work must itself be a software library. 1171 | 1172 | b) You must cause the files modified to carry prominent notices 1173 | stating that you changed the files and the date of any change. 1174 | 1175 | c) You must cause the whole of the work to be licensed at no 1176 | charge to all third parties under the terms of this License. 1177 | 1178 | d) If a facility in the modified Library refers to a function or a 1179 | table of data to be supplied by an application program that uses 1180 | the facility, other than as an argument passed when the facility 1181 | is invoked, then you must make a good faith effort to ensure that, 1182 | in the event an application does not supply such function or 1183 | table, the facility still operates, and performs whatever part of 1184 | its purpose remains meaningful. 1185 | 1186 | (For example, a function in a library to compute square roots has 1187 | a purpose that is entirely well-defined independent of the 1188 | application. Therefore, Subsection 2d requires that any 1189 | application-supplied function or table used by this function must 1190 | be optional: if the application does not supply it, the square 1191 | root function must still compute square roots.) 1192 | 1193 | These requirements apply to the modified work as a whole. If 1194 | identifiable sections of that work are not derived from the Library, 1195 | and can be reasonably considered independent and separate works in 1196 | themselves, then this License, and its terms, do not apply to those 1197 | sections when you distribute them as separate works. But when you 1198 | distribute the same sections as part of a whole which is a work based 1199 | on the Library, the distribution of the whole must be on the terms of 1200 | this License, whose permissions for other licensees extend to the 1201 | entire whole, and thus to each and every part regardless of who wrote 1202 | it. 1203 | 1204 | Thus, it is not the intent of this section to claim rights or contest 1205 | your rights to work written entirely by you; rather, the intent is to 1206 | exercise the right to control the distribution of derivative or 1207 | collective works based on the Library. 1208 | 1209 | In addition, mere aggregation of another work not based on the Library 1210 | with the Library (or with a work based on the Library) on a volume of 1211 | a storage or distribution medium does not bring the other work under 1212 | the scope of this License. 1213 | 1214 | 3. You may opt to apply the terms of the ordinary GNU General Public 1215 | License instead of this License to a given copy of the Library. To do 1216 | this, you must alter all the notices that refer to this License, so 1217 | that they refer to the ordinary GNU General Public License, version 2, 1218 | instead of to this License. (If a newer version than version 2 of the 1219 | ordinary GNU General Public License has appeared, then you can specify 1220 | that version instead if you wish.) Do not make any other change in 1221 | these notices. 1222 | 1223 | Once this change is made in a given copy, it is irreversible for 1224 | that copy, so the ordinary GNU General Public License applies to all 1225 | subsequent copies and derivative works made from that copy. 1226 | 1227 | This option is useful when you wish to copy part of the code of 1228 | the Library into a program that is not a library. 1229 | 1230 | 4. You may copy and distribute the Library (or a portion or 1231 | derivative of it, under Section 2) in object code or executable form 1232 | under the terms of Sections 1 and 2 above provided that you accompany 1233 | it with the complete corresponding machine-readable source code, which 1234 | must be distributed under the terms of Sections 1 and 2 above on a 1235 | medium customarily used for software interchange. 1236 | 1237 | If distribution of object code is made by offering access to copy 1238 | from a designated place, then offering equivalent access to copy the 1239 | source code from the same place satisfies the requirement to 1240 | distribute the source code, even though third parties are not 1241 | compelled to copy the source along with the object code. 1242 | 1243 | 5. A program that contains no derivative of any portion of the 1244 | Library, but is designed to work with the Library by being compiled or 1245 | linked with it, is called a "work that uses the Library". Such a 1246 | work, in isolation, is not a derivative work of the Library, and 1247 | therefore falls outside the scope of this License. 1248 | 1249 | However, linking a "work that uses the Library" with the Library 1250 | creates an executable that is a derivative of the Library (because it 1251 | contains portions of the Library), rather than a "work that uses the 1252 | library". The executable is therefore covered by this License. 1253 | Section 6 states terms for distribution of such executables. 1254 | 1255 | When a "work that uses the Library" uses material from a header file 1256 | that is part of the Library, the object code for the work may be a 1257 | derivative work of the Library even though the source code is not. 1258 | Whether this is true is especially significant if the work can be 1259 | linked without the Library, or if the work is itself a library. The 1260 | threshold for this to be true is not precisely defined by law. 1261 | 1262 | If such an object file uses only numerical parameters, data 1263 | structure layouts and accessors, and small macros and small inline 1264 | functions (ten lines or less in length), then the use of the object 1265 | file is unrestricted, regardless of whether it is legally a derivative 1266 | work. (Executables containing this object code plus portions of the 1267 | Library will still fall under Section 6.) 1268 | 1269 | Otherwise, if the work is a derivative of the Library, you may 1270 | distribute the object code for the work under the terms of Section 6. 1271 | Any executables containing that work also fall under Section 6, 1272 | whether or not they are linked directly with the Library itself. 1273 | 1274 | 6. As an exception to the Sections above, you may also combine or 1275 | link a "work that uses the Library" with the Library to produce a 1276 | work containing portions of the Library, and distribute that work 1277 | under terms of your choice, provided that the terms permit 1278 | modification of the work for the customer's own use and reverse 1279 | engineering for debugging such modifications. 1280 | 1281 | You must give prominent notice with each copy of the work that the 1282 | Library is used in it and that the Library and its use are covered by 1283 | this License. You must supply a copy of this License. If the work 1284 | during execution displays copyright notices, you must include the 1285 | copyright notice for the Library among them, as well as a reference 1286 | directing the user to the copy of this License. Also, you must do one 1287 | of these things: 1288 | 1289 | a) Accompany the work with the complete corresponding 1290 | machine-readable source code for the Library including whatever 1291 | changes were used in the work (which must be distributed under 1292 | Sections 1 and 2 above); and, if the work is an executable linked 1293 | with the Library, with the complete machine-readable "work that 1294 | uses the Library", as object code and/or source code, so that the 1295 | user can modify the Library and then relink to produce a modified 1296 | executable containing the modified Library. (It is understood 1297 | that the user who changes the contents of definitions files in the 1298 | Library will not necessarily be able to recompile the application 1299 | to use the modified definitions.) 1300 | 1301 | b) Use a suitable shared library mechanism for linking with the 1302 | Library. A suitable mechanism is one that (1) uses at run time a 1303 | copy of the library already present on the user's computer system, 1304 | rather than copying library functions into the executable, and (2) 1305 | will operate properly with a modified version of the library, if 1306 | the user installs one, as long as the modified version is 1307 | interface-compatible with the version that the work was made with. 1308 | 1309 | c) Accompany the work with a written offer, valid for at 1310 | least three years, to give the same user the materials 1311 | specified in Subsection 6a, above, for a charge no more 1312 | than the cost of performing this distribution. 1313 | 1314 | d) If distribution of the work is made by offering access to copy 1315 | from a designated place, offer equivalent access to copy the above 1316 | specified materials from the same place. 1317 | 1318 | e) Verify that the user has already received a copy of these 1319 | materials or that you have already sent this user a copy. 1320 | 1321 | For an executable, the required form of the "work that uses the 1322 | Library" must include any data and utility programs needed for 1323 | reproducing the executable from it. However, as a special exception, 1324 | the materials to be distributed need not include anything that is 1325 | normally distributed (in either source or binary form) with the major 1326 | components (compiler, kernel, and so on) of the operating system on 1327 | which the executable runs, unless that component itself accompanies 1328 | the executable. 1329 | 1330 | It may happen that this requirement contradicts the license 1331 | restrictions of other proprietary libraries that do not normally 1332 | accompany the operating system. Such a contradiction means you cannot 1333 | use both them and the Library together in an executable that you 1334 | distribute. 1335 | 1336 | 7. You may place library facilities that are a work based on the 1337 | Library side-by-side in a single library together with other library 1338 | facilities not covered by this License, and distribute such a combined 1339 | library, provided that the separate distribution of the work based on 1340 | the Library and of the other library facilities is otherwise 1341 | permitted, and provided that you do these two things: 1342 | 1343 | a) Accompany the combined library with a copy of the same work 1344 | based on the Library, uncombined with any other library 1345 | facilities. This must be distributed under the terms of the 1346 | Sections above. 1347 | 1348 | b) Give prominent notice with the combined library of the fact 1349 | that part of it is a work based on the Library, and explaining 1350 | where to find the accompanying uncombined form of the same work. 1351 | 1352 | 8. You may not copy, modify, sublicense, link with, or distribute 1353 | the Library except as expressly provided under this License. Any 1354 | attempt otherwise to copy, modify, sublicense, link with, or 1355 | distribute the Library is void, and will automatically terminate your 1356 | rights under this License. However, parties who have received copies, 1357 | or rights, from you under this License will not have their licenses 1358 | terminated so long as such parties remain in full compliance. 1359 | 1360 | 9. You are not required to accept this License, since you have not 1361 | signed it. However, nothing else grants you permission to modify or 1362 | distribute the Library or its derivative works. These actions are 1363 | prohibited by law if you do not accept this License. Therefore, by 1364 | modifying or distributing the Library (or any work based on the 1365 | Library), you indicate your acceptance of this License to do so, and 1366 | all its terms and conditions for copying, distributing or modifying 1367 | the Library or works based on it. 1368 | 1369 | 10. Each time you redistribute the Library (or any work based on the 1370 | Library), the recipient automatically receives a license from the 1371 | original licensor to copy, distribute, link with or modify the Library 1372 | subject to these terms and conditions. You may not impose any further 1373 | restrictions on the recipients' exercise of the rights granted herein. 1374 | You are not responsible for enforcing compliance by third parties with 1375 | this License. 1376 | 1377 | 11. If, as a consequence of a court judgment or allegation of patent 1378 | infringement or for any other reason (not limited to patent issues), 1379 | conditions are imposed on you (whether by court order, agreement or 1380 | otherwise) that contradict the conditions of this License, they do not 1381 | excuse you from the conditions of this License. If you cannot 1382 | distribute so as to satisfy simultaneously your obligations under this 1383 | License and any other pertinent obligations, then as a consequence you 1384 | may not distribute the Library at all. For example, if a patent 1385 | license would not permit royalty-free redistribution of the Library by 1386 | all those who receive copies directly or indirectly through you, then 1387 | the only way you could satisfy both it and this License would be to 1388 | refrain entirely from distribution of the Library. 1389 | 1390 | If any portion of this section is held invalid or unenforceable under any 1391 | particular circumstance, the balance of the section is intended to apply, 1392 | and the section as a whole is intended to apply in other circumstances. 1393 | 1394 | It is not the purpose of this section to induce you to infringe any 1395 | patents or other property right claims or to contest validity of any 1396 | such claims; this section has the sole purpose of protecting the 1397 | integrity of the free software distribution system which is 1398 | implemented by public license practices. Many people have made 1399 | generous contributions to the wide range of software distributed 1400 | through that system in reliance on consistent application of that 1401 | system; it is up to the author/donor to decide if he or she is willing 1402 | to distribute software through any other system and a licensee cannot 1403 | impose that choice. 1404 | 1405 | This section is intended to make thoroughly clear what is believed to 1406 | be a consequence of the rest of this License. 1407 | 1408 | 12. If the distribution and/or use of the Library is restricted in 1409 | certain countries either by patents or by copyrighted interfaces, the 1410 | original copyright holder who places the Library under this License may add 1411 | an explicit geographical distribution limitation excluding those countries, 1412 | so that distribution is permitted only in or among countries not thus 1413 | excluded. In such case, this License incorporates the limitation as if 1414 | written in the body of this License. 1415 | 1416 | 13. The Free Software Foundation may publish revised and/or new 1417 | versions of the Lesser General Public License from time to time. 1418 | Such new versions will be similar in spirit to the present version, 1419 | but may differ in detail to address new problems or concerns. 1420 | 1421 | Each version is given a distinguishing version number. If the Library 1422 | specifies a version number of this License which applies to it and 1423 | "any later version", you have the option of following the terms and 1424 | conditions either of that version or of any later version published by 1425 | the Free Software Foundation. If the Library does not specify a 1426 | license version number, you may choose any version ever published by 1427 | the Free Software Foundation. 1428 | 1429 | 14. If you wish to incorporate parts of the Library into other free 1430 | programs whose distribution conditions are incompatible with these, 1431 | write to the author to ask for permission. For software which is 1432 | copyrighted by the Free Software Foundation, write to the Free 1433 | Software Foundation; we sometimes make exceptions for this. Our 1434 | decision will be guided by the two goals of preserving the free status 1435 | of all derivatives of our free software and of promoting the sharing 1436 | and reuse of software generally. 1437 | 1438 | NO WARRANTY 1439 | 1440 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 1441 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 1442 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 1443 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 1444 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 1445 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 1446 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 1447 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 1448 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 1449 | 1450 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 1451 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 1452 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 1453 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 1454 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 1455 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 1456 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 1457 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 1458 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 1459 | DAMAGES. 1460 | 1461 | END OF TERMS AND CONDITIONS 1462 | 1463 | How to Apply These Terms to Your New Libraries 1464 | 1465 | If you develop a new library, and you want it to be of the greatest 1466 | possible use to the public, we recommend making it free software that 1467 | everyone can redistribute and change. You can do so by permitting 1468 | redistribution under these terms (or, alternatively, under the terms of the 1469 | ordinary General Public License). 1470 | 1471 | To apply these terms, attach the following notices to the library. It is 1472 | safest to attach them to the start of each source file to most effectively 1473 | convey the exclusion of warranty; and each file should have at least the 1474 | "copyright" line and a pointer to where the full notice is found. 1475 | 1476 | 1477 | Copyright (C) 1478 | 1479 | This library is free software; you can redistribute it and/or 1480 | modify it under the terms of the GNU Lesser General Public 1481 | License as published by the Free Software Foundation; either 1482 | version 2.1 of the License, or (at your option) any later version. 1483 | 1484 | This library is distributed in the hope that it will be useful, 1485 | but WITHOUT ANY WARRANTY; without even the implied warranty of 1486 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1487 | Lesser General Public License for more details. 1488 | 1489 | You should have received a copy of the GNU Lesser General Public 1490 | License along with this library; if not, write to the Free Software 1491 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 1492 | 1493 | Also add information on how to contact you by electronic and paper mail. 1494 | 1495 | You should also get your employer (if you work as a programmer) or your 1496 | school, if any, to sign a "copyright disclaimer" for the library, if 1497 | necessary. Here is a sample; alter the names: 1498 | 1499 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 1500 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 1501 | 1502 | , 1 April 1990 1503 | Ty Coon, President of Vice 1504 | 1505 | That's all there is to it! 1506 | 1507 | 1508 | 1509 | 1510 | =============================================================================== 1511 | ### idna@2.10 (BSD-3-Clause) 1512 | 1513 | License 1514 | ------- 1515 | 1516 | License: bsd-3-clause 1517 | 1518 | Copyright (c) 2013-2020, Kim Davies. All rights reserved. 1519 | 1520 | Redistribution and use in source and binary forms, with or without 1521 | modification, are permitted provided that the following conditions are met: 1522 | 1523 | #. Redistributions of source code must retain the above copyright 1524 | notice, this list of conditions and the following disclaimer. 1525 | 1526 | #. Redistributions in binary form must reproduce the above 1527 | copyright notice, this list of conditions and the following 1528 | disclaimer in the documentation and/or other materials provided with 1529 | the distribution. 1530 | 1531 | #. Neither the name of the copyright holder nor the names of the 1532 | contributors may be used to endorse or promote products derived 1533 | from this software without specific prior written permission. 1534 | 1535 | #. THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS "AS IS" AND ANY 1536 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1537 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 1538 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 1539 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1540 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1541 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1542 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1543 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1544 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 1545 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 1546 | DAMAGE. 1547 | 1548 | 1549 | =============================================================================== 1550 | ### urllib3@1.25.11 (MIT) 1551 | 1552 | MIT License 1553 | --------------------------------------------------------------------------------