Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/Ajay-aot/forms-flow-ai i…
Browse files Browse the repository at this point in the history
…nto Feature/FWF-3620-reusable-history-component
  • Loading branch information
Ajay-aot committed Oct 30, 2024
2 parents ccb3732 + ffaf673 commit 82acc63
Show file tree
Hide file tree
Showing 20 changed files with 804 additions and 447 deletions.
86 changes: 86 additions & 0 deletions .github/workflows/pr-notification.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: PR Notification to Google Chat

on:
pull_request:
types: [opened, synchronize, closed]
branches:
- develop

jobs:
notify:
runs-on: ubuntu-latest
if: github.event.pull_request.base.repo.full_name == 'AOT-Technologies/forms-flow-ai'

steps:
- name: Determine PR Status
id: pr_status
run: |
if [[ "${{ github.event.action }}" == "opened" ]]; then
echo "status=🟢 Open" >> $GITHUB_ENV
elif [[ "${{ github.event.action }}" == "closed" && "${{ github.event.pull_request.merged }}" == "true" ]]; then
echo "status=🟣 Merged" >> $GITHUB_ENV
elif [[ "${{ github.event.action }}" == "closed" ]]; then
echo "status=🔴 Closed" >> $GITHUB_ENV
else
echo "status=🟢 Open" >> $GITHUB_ENV
fi
- name: Confirm PR_NOTIFICATION Secret is Set
run: |
if [[ -z "${{ secrets.PR_NOTIFICATION }}" ]]; then
echo "PR_NOTIFICATION secret is not set."
else
echo "PR_NOTIFICATION secret is set."
fi
- name: Send notification to Google Chat
uses: fjogeleit/[email protected]
with:
url: ${{ secrets.PR_NOTIFICATION }}

method: POST
contentType: application/json
data: |
{
"cards": [
{
"header": {
"title": "Open source: Pull Request Opened by ${{ github.event.pull_request.user.login }}",
"subtitle": "Pull Request #${{ github.event.pull_request.number }}: ${{ github.event.pull_request.title }}",
"imageUrl": "${{ github.event.pull_request.user.avatar_url }}"
},
"sections": [
{
"widgets": [
{
"textParagraph": {
"text": "Repository: ${{ github.repository }}"
}
},
{
"textParagraph": {
"text": "Status: ${{ env.status }}"
}
},
{
"buttons": [
{
"textButton": {
"text": "View Pull Request",
"onClick": {
"openLink": {
"url": "${{ github.event.pull_request.html_url }}"
}
}
}
}
]
}
]
}
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,12 @@ def status_code(self):
class BusinessException(Exception):
"""Exception that adds error code and error."""

def __init__(self, error_code: ErrorCodeMixin, details=None, detail_message=None):
def __init__(self, error_code: ErrorCodeMixin, details=None, detail_message=None, include_details=False):
super().__init__(error_code.message)
self.message = error_code.message

# Include the detailed message in the main message if include_details is True
self.message = detail_message if include_details and detail_message else error_code.message

self.code = error_code.code
self.status_code = error_code.status_code
if detail_message:
Expand Down
2 changes: 1 addition & 1 deletion forms-flow-api/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ exceptiongroup==1.2.2
flask-jwt-oidc==0.7.0
flask-marshmallow==1.2.1
flask-restx==1.3.0
formsflow_api_utils @ git+https://github.com/AOT-Technologies/forms-flow-ai.git@develop#subdirectory=forms-flow-api-utils
formsflow_api_utils @ git+https://github.com/auslin-aot/forms-flow-ai.git@fwf-3769-form-validation-changes#subdirectory=forms-flow-api-utils
gunicorn==23.0.0
h11==0.14.0
h2==4.1.0
Expand Down
2 changes: 1 addition & 1 deletion forms-flow-api/requirements/prod.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ markupsafe
PyJWT
redis
lxml
git+https://github.com/AOT-Technologies/forms-flow-ai.git@develop#subdirectory=forms-flow-api-utils
git+https://github.com/auslin-aot/forms-flow-ai.git@fwf-3769-form-validation-changes#subdirectory=forms-flow-api-utils
5 changes: 5 additions & 0 deletions forms-flow-api/src/formsflow_api/constants/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ class BusinessErrorCode(ErrorCodeMixin, Enum):
"Cannot update a published process",
HTTPStatus.BAD_REQUEST,
)
FORM_INVALID_OPERATION = (
"Cannot update a published form",
HTTPStatus.BAD_REQUEST,
)
FORM_VALIDATION_FAILED = "FORM_VALIDATION_FAILED.", HTTPStatus.BAD_REQUEST

def __new__(cls, message, status_code):
"""Constructor."""
Expand Down
4 changes: 1 addition & 3 deletions forms-flow-api/src/formsflow_api/models/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ def subquery_for_getting_latest_process(cls):
db.session.query(
cls.parent_process_key,
func.max(cls.major_version).label("latest_major_version"),
func.max(cls.minor_version).label("latest_minor_version"),
func.max(cls.id).label("latest_id"),
)
.group_by(cls.parent_process_key)
Expand All @@ -165,7 +164,6 @@ def find_all_process( # pylint: disable=too-many-arguments, too-many-positional
subquery,
(cls.parent_process_key == subquery.c.parent_process_key)
& (cls.major_version == subquery.c.latest_major_version)
& (cls.minor_version == subquery.c.latest_minor_version)
& (cls.id == subquery.c.latest_id),
)

Expand All @@ -185,7 +183,7 @@ def get_latest_version_by_key(cls, process_key):
"""Get latest version of process."""
query = (
cls.auth_query(cls.query.filter(cls.process_key == process_key))
.order_by(cls.major_version.desc(), cls.minor_version.desc())
.order_by(cls.major_version.desc(), cls.minor_version.desc(), cls.id.desc())
.first()
)

Expand Down
43 changes: 43 additions & 0 deletions forms-flow-api/src/formsflow_api/services/form_process_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,47 @@ def export( # pylint:disable=too-many-locals

raise BusinessException(BusinessErrorCode.INVALID_FORM_PROCESS_MAPPER_ID)

@classmethod
def is_valid_field(cls, field: str, pattern: str) -> bool:
"""Checks if the given field matches the provided regex pattern."""
return bool(re.fullmatch(pattern, field))

@classmethod
def validate_title_name_path(cls, title: str, path: str, name: str):
"""Validates the title, path, and name fields."""
title_pattern = r"(?=.*[A-Za-z])[A-Za-z0-9 ]+"
path_name = r"(?=.*[A-Za-z])[A-Za-z0-9]+"

invalid_fields = []

error_messages = {
"title": "Title: Only contain alphanumeric characters and spaces, and must include at least one letter.",
"path": "Path: Only contain alphanumeric characters, no spaces, and must include at least one letter.",
"name": "Name: Only contain alphanumeric characters, no spaces, and must include at least one letter.",
}

# Validate title
if title and not cls.is_valid_field(title, title_pattern):
invalid_fields.append("title")

# Validate path and name
for field_name, field_value in (("path", path), ("name", name)):
if field_value and not cls.is_valid_field(field_value, path_name):
invalid_fields.append(field_name)

# Determine overall validity
is_valid = len(invalid_fields) == 0
if not is_valid:
# Generate detailed validation error message
error_message = ",\n ".join(
error_messages[field] for field in invalid_fields
)
raise BusinessException(
BusinessErrorCode.FORM_VALIDATION_FAILED,
detail_message=error_message,
include_details=True,
)

@staticmethod
def validate_form_name_path_title(request):
"""Validate a form name by calling the external validation API."""
Expand All @@ -661,6 +702,8 @@ def validate_form_name_path_title(request):
if not (title or name or path):
raise BusinessException(BusinessErrorCode.INVALID_FORM_VALIDATION_INPUT)

FormProcessMapperService.validate_title_name_path(title, path, name)

# Combine them into query parameters dictionary
query_params = f"title={title}&name={name}&path={path}&select=title,path,name"

Expand Down
Loading

0 comments on commit 82acc63

Please sign in to comment.