Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Implements on WhatsApp Demo to use triggers by flows to Start Conversation #180

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
133 changes: 133 additions & 0 deletions .github/workflows/build-integrations-engine-push-tag-shared.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
name: Build Weni Integrations Engine in Shared (Push Tag)

on:
push:
tags:
- '*.*.*-develop'
- '*.*.*-staging'
- '*.*.*'

jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Set variables
run: |
TAG="$( echo "${GITHUB_REF}" | cut -d'/' -f3 )"
if grep -qs -e '^.*.*-develop' <<< "${TAG}" ; then
echo "Found environment: DEVELOP - ${TAG}"
echo "MANIFESTS_ENVIRONMENT=develop" | tee -a "${GITHUB_ENV}"
elif grep -qs -e '^.*.*-staging' <<< "${TAG}" ; then
echo "Found environment: STAGING - ${TAG}"
echo "MANIFESTS_ENVIRONMENT=staging" | tee -a "${GITHUB_ENV}"
elif grep -qs -e '^.*.*' <<< "${TAG}" ; then
echo "No environment found, assuming: PRODUCTION - ${TAG}"
echo "MANIFESTS_ENVIRONMENT=production" | tee -a "${GITHUB_ENV}"
else
echo 'Not a valid tag. Skipping...'
exit 1
fi
echo "TAG=$TAG" | tee -a "${GITHUB_ENV}"
VERSION="${TAG}"
echo "VERSION=${VERSION}" | tee -a "${GITHUB_ENV}"
echo "COMMIT_SHA=$GITHUB_SHA" | tee -a "${GITHUB_ENV}"
echo "IMAGE_TAG=${{ secrets.ECR_SHARED }}/integrations:engine-$TAG" | tee -a "${GITHUB_ENV}"
echo "IMAGE_SOURCE_URL=https://github.com/weni-ai/weni-integrations-engine" | tee -a "${GITHUB_ENV}"
echo "MANIFESTS_REPOSITORY=Ilhasoft/kubernetes-manifests-platform" | tee -a "${GITHUB_ENV}"
echo "MANIFESTS_APPLICATION=integrations-engine" | tee -a "${GITHUB_ENV}"
echo "MANIFESTS_PATCH_TARGET=deployment-engine.json" | tee -a "${GITHUB_ENV}"

- name: Check out the repo
uses: actions/checkout@v3
with:
ref: "${{env.GITHUB_SHA}}"

- name: Set up QEMU
uses: docker/setup-qemu-action@v2

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Login to ECR
uses: docker/login-action@v2
with:
registry: ${{ secrets.ECR_SHARED }}
username: ${{ secrets.AWS_ACCESS_KEY_ID_SHARED }}
password: ${{ secrets.AWS_SECRET_ACCESS_KEY_SHARED }}

- name: Build and push - Weni Integrations Engine Image
uses: docker/build-push-action@v3
with:
context: .
labels: |
tag=${{env.TAG}}
commit=${{env.COMMIT_SHA}}
repository=${{env.IMAGE_SOURCE_URL}}
file: docker/Dockerfile
push: true
tags: "${{env.IMAGE_TAG}}"
no-cache: true

- name: Check out Kubernetes Manifests
uses: actions/checkout@master
with:
ref: main
repository: "${{ env.MANIFESTS_REPOSITORY }}"
token: "${{ secrets.DEVOPS_GITHUB_PERMANENT_TOKEN }}"
path: ./kubernetes-manifests/

- name: Update image on deployment
run: |
which jq > /dev/null 2>&1 || ( sudo apt update ; sudo apt install -y jq )
# Dep: coreutils
verlte() {
[ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]
}
verlt(){
[ "$1" = "$2" ] && return 1 || verlte $1 $2
}
export PROJECT_DIR="${{ env.MANIFESTS_APPLICATION }}"
ENV_DIR="kubernetes-manifests/${{ env.MANIFESTS_APPLICATION }}/${MANIFESTS_ENVIRONMENT}"
for e in ${ENV_DIR}; do
echo "Update ${e}:"
if [ ! -d "${e}" ] ; then
echo "${e}: Does not exist, skipping"
elif [ ! -r "${e}/kustomization.yaml" ] ; then
echo "${e}/kustomization.yaml: Does not readable, skipping"
elif [ ! -r "${e}/${{ env.MANIFESTS_PATCH_TARGET }}" ] ; then
echo "${e}/${{ env.MANIFESTS_PATCH_TARGET }}: Does not readable, skipping"
else
OLD_IMAGE=$(
cat "${e}/${{ env.MANIFESTS_PATCH_TARGET }}" \
| jq '.[] | select(.path == "/spec/template/spec/containers/0/image") | .value'
)
echo "Old image to replace: ${OLD_IMAGE}"
OLD_VERSION=$(
echo "${OLD_IMAGE}" \
| sed s'/^.*[v:-]\([0-9]*\.[0-9]*\.[0-9]*\).*$/\1/'g \
| head -n1
)
echo "Old image version to compare: ${OLD_VERSION}<=${{env.VERSION}}"
if verlte "${OLD_VERSION}" "${VERSION}" || [[ ! "${OLD_VERSION}" =~ [0-9]+\.[0-9]+\.[0-9]+ ]] ; then
echo 'New configurations:'
new_configuration=$(
cat "${e}/${{ env.MANIFESTS_PATCH_TARGET }}" \
| jq '(..|select(.path == "/spec/template/spec/containers/0/image")?) += {value: "'"${{env.IMAGE_TAG}}"'"}'
)
echo "${new_configuration}"
echo "${new_configuration}" > "${e}/${{ env.MANIFESTS_PATCH_TARGET }}"
else
echo "Version in file is greater than build, skipping update yaml"
fi
fi
done

- name: Commit & Push changes
uses: actions-js/push@master
with:
github_token: "${{ secrets.DEVOPS_GITHUB_PERMANENT_TOKEN }}"
repository: "${{ env.MANIFESTS_REPOSITORY }}"
directory: ./kubernetes-manifests/
branch: main
message: "From Weni Integrations Engine Build (Push Tag ${{ env.MANIFESTS_ENVIRONMENT }})"

29 changes: 29 additions & 0 deletions marketplace/connect/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,27 @@ def release_channel(self, channel_uuid: str, user_email: str) -> None:
)
return None

def list_flows(self, project_uuid):
""" This function return
{
"uuid": "...", # flows uuid
"name": "...", # flows name
"triggers": [
{
"keyword": "...",
"trigger_type": "...",
"id": 1
},
...
]
}
"""
response = requests.get(
url=self.base_url + f"/v1/organization/project/{project_uuid}/list_flows/?project_uuid={project_uuid}",
headers=self.auth_header()
)
return response.json()


class WPPRouterChannelClient(ConnectAuth):
base_url = settings.ROUTER_BASE_URL
Expand All @@ -71,3 +92,11 @@ def get_channel_token(self, uuid: str, name: str) -> str:
response = requests.post(url=self.base_url + "/integrations/channel", json=payload, headers=self.auth_header())

return response.json().get("token", "")

def set_flows_starts(self, flows_starts: dict, channel_uuid: str) -> None:
payload = {
"flows_starts": flows_starts,
"channel_uuid": channel_uuid
}
requests.post(url=self.base_url + "/integrations/flows", json=payload, headers=self.auth_header())
return None
11 changes: 11 additions & 0 deletions marketplace/core/types/channels/whatsapp_demo/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

from marketplace.applications.models import App
from marketplace.core.serializers import AppTypeBaseSerializer
from marketplace.connect.client import ConnectProjectClient


class WhatsAppDemoSerializer(AppTypeBaseSerializer):

redirect_url = serializers.SerializerMethodField()
flows_starts = serializers.SerializerMethodField()

class Meta:
model = App
Expand All @@ -20,6 +22,7 @@ class Meta:
"created_on",
"modified_by",
"redirect_url",
"flows_starts",
)
read_only_fields = ("code", "uuid", "platform")

Expand All @@ -31,3 +34,11 @@ def create(self, validated_data):

def get_redirect_url(self, instance) -> str:
return instance.config.get("redirect_url")

def get_flows_starts(self, instance):
"""
Returns entity-related flows
"""
client = ConnectProjectClient()
flows_starts = client.list_flows(instance.project_uuid.hex)
return flows_starts
46 changes: 46 additions & 0 deletions marketplace/core/types/channels/whatsapp_demo/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,52 @@ def test_retrieve_app_data(self):
self.assertEqual(response.json["config"], {})


class UpdateWhatsAppDemoAppTestCase(APIBaseTestCase):
view_class = WhatsAppDemoViewSet

def setUp(self):
""" App creation and authorization configuration """
super().setUp()

self.app = App.objects.create(
code="wpp-demo",
created_by=self.user,
project_uuid=str(uuid.uuid4()),
flow_object_uuid=str(uuid.uuid4()),
platform=App.PLATFORM_WENI_FLOWS
)
self.user_authorization = self.user.authorizations.create(
project_uuid=self.app.project_uuid, role=ProjectAuthorization.ROLE_ADMIN
)
self.url = reverse("wpp-demo-app-detail", kwargs={"uuid": self.app.uuid})

@property
def view(self):
return self.view_class.as_view({"patch": "partial_update"})

def test_partial_update(self):
"""
Partial update to flows
"""
data = {
"flows_starts": {
"uuid": "3a624a22-c825-461c-9bcf-2fdf7c38eb74",
"name": "flow_02",
"triggers": [
{
"keyword": "hello",
"trigger_type": "...",
"id": 1
},

],
}
}
response = self.request.patch(self.url, uuid=self.app.uuid, body=data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data.get("config").get("flows_starts"), data.get("flows_starts"))


class DestroyWhatsAppDemoAppTestCase(APIBaseTestCase):
view_class = WhatsAppDemoViewSet

Expand Down
22 changes: 22 additions & 0 deletions marketplace/core/types/channels/whatsapp_demo/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
from .serializers import WhatsAppDemoSerializer
from marketplace.connect.client import ConnectProjectClient, WPPRouterChannelClient

from rest_framework.response import Response
from rest_framework import status


class WhatsAppDemoViewSet(views.BaseAppTypeViewSet):

Expand Down Expand Up @@ -41,3 +44,22 @@ def perform_create(self, serializer):
instance.config["redirect_url"] = f"https://wa.me/{type_class.NUMBER}?text={channel_token}"
instance.modified_by = user
instance.save()

def partial_update(self, request, *args, **kwargs):
instance = self.get_object()
print('debug# 1')
flows_starts = request.data.get("flows_starts")
if not flows_starts:
print('debug# 2')
return Response({'message': f'the flows_starts not found in request: {request.data}'},
status=status.HTTP_404_NOT_FOUND)
print('debug# 3')
instance.config["flows_starts"] = flows_starts
instance.modified_by = self.request.user
instance.save()
print('debug# 4')
channel_client = WPPRouterChannelClient()
channel_client.set_flows_starts(flows_starts, instance.flow_object_uuid.hex)
serializer = self.get_serializer(instance)
print('debug# 5')
return Response(serializer.data, status.HTTP_201_CREATED)