-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
1 parent
8366029
commit c27ddcd
Showing
12 changed files
with
751 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
met-api/migrations/versions/c4f7189494ed_create_engagement_translation_table.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
"""create_engagement_translation_table | ||
Revision ID: c4f7189494ed | ||
Revises: 35124d2e41cb | ||
Create Date: 2024-03-07 16:38:26.958748 | ||
""" | ||
from alembic import op | ||
import sqlalchemy as sa | ||
from sqlalchemy.dialects import postgresql | ||
|
||
# revision identifiers, used by Alembic. | ||
revision = 'c4f7189494ed' | ||
down_revision = '35124d2e41cb' | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade(): | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.create_table('engagement_translation', | ||
sa.Column('created_date', sa.DateTime(), nullable=False), | ||
sa.Column('updated_date', sa.DateTime(), nullable=True), | ||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), | ||
sa.Column('engagement_id', sa.Integer(), nullable=False), | ||
sa.Column('language_id', sa.Integer(), nullable=False), | ||
sa.Column('name', sa.String(length=50), nullable=True), | ||
sa.Column('description', sa.Text(), nullable=True), | ||
sa.Column('rich_description', postgresql.JSON(astext_type=sa.Text()), nullable=True), | ||
sa.Column('content', sa.Text(), nullable=True), | ||
sa.Column('rich_content', postgresql.JSON(astext_type=sa.Text()), nullable=True), | ||
sa.Column('consent_message', postgresql.JSON(astext_type=sa.Text()), nullable=True), | ||
sa.Column('slug', sa.String(length=200), nullable=True), | ||
sa.Column('upcoming_status_block_text', postgresql.JSON(astext_type=sa.Text()), nullable=True), | ||
sa.Column('open_status_block_text', postgresql.JSON(astext_type=sa.Text()), nullable=True), | ||
sa.Column('closed_status_block_text', postgresql.JSON(astext_type=sa.Text()), nullable=True), | ||
sa.Column('created_by', sa.String(length=50), nullable=True), | ||
sa.Column('updated_by', sa.String(length=50), nullable=True), | ||
sa.ForeignKeyConstraint(['engagement_id'], ['engagement.id'], ondelete='CASCADE'), | ||
sa.ForeignKeyConstraint(['language_id'], ['language.id'], ondelete='CASCADE'), | ||
sa.PrimaryKeyConstraint('id'), | ||
sa.UniqueConstraint('engagement_id', 'language_id', name='_engagement_language_uc') | ||
) | ||
# ### end Alembic commands ### | ||
|
||
|
||
def downgrade(): | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.drop_table('engagement_translation') | ||
# ### end Alembic commands ### |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
"""Engagement translation model class. | ||
Manages the Engagement Translations. | ||
""" | ||
|
||
from __future__ import annotations | ||
from typing import Optional | ||
|
||
from sqlalchemy import UniqueConstraint | ||
from sqlalchemy.dialects.postgresql import JSON | ||
|
||
from .base_model import BaseModel | ||
from .db import db | ||
|
||
|
||
class EngagementTranslation(BaseModel): | ||
"""Definition of the Engagement Translation entity.""" | ||
|
||
__tablename__ = 'engagement_translation' | ||
|
||
id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
engagement_id = db.Column(db.Integer, db.ForeignKey('engagement.id', ondelete='CASCADE'), nullable=False) | ||
language_id = db.Column(db.Integer, db.ForeignKey('language.id', ondelete='CASCADE'), nullable=False) | ||
name = db.Column(db.String(50)) | ||
description = db.Column(db.Text()) | ||
rich_description = db.Column(JSON, unique=False, nullable=True) | ||
content = db.Column(db.Text()) | ||
rich_content = db.Column(JSON, unique=False, nullable=True) | ||
consent_message = db.Column(JSON, unique=False, nullable=True) | ||
slug = db.Column(db.String(200)) | ||
upcoming_status_block_text = db.Column(JSON, unique=False, nullable=True) | ||
open_status_block_text = db.Column(JSON, unique=False, nullable=True) | ||
closed_status_block_text = db.Column(JSON, unique=False, nullable=True) | ||
|
||
# Add a unique constraint on engagement_id and language_id | ||
# A engagement has only one version in a particular language | ||
__table_args__ = ( | ||
UniqueConstraint( | ||
'engagement_id', 'language_id', name='_engagement_language_uc' | ||
), | ||
) | ||
|
||
@staticmethod | ||
def get_engagement_translation_by_engagement_and_language( | ||
engagement_id=None, language_id=None | ||
): | ||
"""Get engagement translation by engagement_id and language_id, or by either one.""" | ||
query = EngagementTranslation.query | ||
if engagement_id is not None: | ||
query = query.filter_by(engagement_id=engagement_id) | ||
if language_id is not None: | ||
query = query.filter_by(language_id=language_id) | ||
|
||
engagement_translation_records = query.all() | ||
return engagement_translation_records | ||
|
||
@classmethod | ||
def create_engagement_translation(cls, data): | ||
"""Create a new engagement translation.""" | ||
engagement_translation = cls.__create_new_engagement_translation_entity(data) | ||
db.session.add(engagement_translation) | ||
db.session.commit() | ||
return engagement_translation | ||
|
||
@staticmethod | ||
def __create_new_engagement_translation_entity(data): | ||
"""Create new engagement translation entity.""" | ||
return EngagementTranslation( | ||
engagement_id=data.get('engagement_id'), | ||
language_id=data.get('language_id'), | ||
name=data.get('name', None), | ||
description=data.get('description', None), | ||
rich_description=data.get('rich_description', None), | ||
content=data.get('content', None), | ||
rich_content=data.get('rich_content', None), | ||
consent_message=data.get('consent_message', None), | ||
slug=data.get('slug', None), | ||
upcoming_status_block_text=data.get('upcoming_status_block_text', None), | ||
open_status_block_text=data.get('open_status_block_text', None), | ||
closed_status_block_text=data.get('closed_status_block_text', None), | ||
) | ||
|
||
@staticmethod | ||
def update_engagement_translation(engagement_translation_id, data: dict) -> Optional[EngagementTranslation]: | ||
"""Update an existing engagement translation.""" | ||
query = EngagementTranslation.query.filter_by(id=engagement_translation_id) | ||
engagement_translation: EngagementTranslation = query.first() | ||
if not engagement_translation: | ||
return None | ||
query.update(data) | ||
db.session.commit() | ||
return engagement_translation | ||
|
||
@staticmethod | ||
def delete_engagement_translation(engagement_translation_id): | ||
"""Delete a engagement translation.""" | ||
engagement_translation = EngagementTranslation.query.get(engagement_translation_id) | ||
if engagement_translation: | ||
db.session.delete(engagement_translation) | ||
db.session.commit() | ||
return True | ||
return False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
met-api/src/met_api/resources/engagement_translation.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
# Copyright © 2021 Province of British Columbia | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the 'License'); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an 'AS IS' BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
"""API endpoints for managing an engagement translation resource.""" | ||
|
||
from http import HTTPStatus | ||
|
||
from flask import jsonify, request | ||
from flask_cors import cross_origin | ||
from flask_restx import Namespace, Resource | ||
from marshmallow import ValidationError | ||
|
||
from met_api.auth import jwt as _jwt | ||
from met_api.exceptions.business_exception import BusinessException | ||
from met_api.schemas import utils as schema_utils | ||
from met_api.schemas.engagement_translation import EngagementTranslationSchema | ||
from met_api.services.engagement_translation_service import EngagementTranslationService | ||
from met_api.utils.util import allowedorigins, cors_preflight | ||
|
||
|
||
API = Namespace('engagement_translation', description='Endpoints for Engagement translation Management') | ||
|
||
|
||
@cors_preflight('GET, OPTIONS') | ||
@API.route('/language/<int:language_id>') | ||
class EngagementTranslationResourceByLanguage(Resource): | ||
"""Resource for managing a engagement translation.""" | ||
|
||
@staticmethod | ||
@cross_origin(origins=allowedorigins()) | ||
def get(engagement_id, language_id): | ||
"""Fetch a engagement by widget_id and language_id.""" | ||
try: | ||
engagement = EngagementTranslationService().get_translation_by_engagement_and_language( | ||
engagement_id, language_id) | ||
return jsonify(engagement), HTTPStatus.OK | ||
except (KeyError, ValueError) as err: | ||
return str(err), HTTPStatus.INTERNAL_SERVER_ERROR | ||
|
||
|
||
@cors_preflight('POST, OPTIONS') | ||
@API.route('/') | ||
class EngagementTranslations(Resource): | ||
"""Resource for creating a engagement translation.""" | ||
|
||
@staticmethod | ||
@cross_origin(origins=allowedorigins()) | ||
@_jwt.requires_auth | ||
def post(engagement_id): | ||
"""Add new engagement translation.""" | ||
try: | ||
request_json = request.get_json() | ||
request_json['engagement_id'] = engagement_id | ||
valid_format, errors = schema_utils.validate(request_json, 'engagement_translation') | ||
if not valid_format: | ||
return {'message': schema_utils.serialize(errors)}, HTTPStatus.BAD_REQUEST | ||
|
||
pre_populate = request_json.get('pre_populate', True) | ||
|
||
engagement_translation = EngagementTranslationSchema().load(request_json) | ||
created_engagement_translation = EngagementTranslationService().create_engagement_translation( | ||
engagement_translation, pre_populate) | ||
return created_engagement_translation, HTTPStatus.OK | ||
except (KeyError, ValueError) as err: | ||
return str(err), HTTPStatus.INTERNAL_SERVER_ERROR | ||
except ValidationError as err: | ||
return str(err.messages), HTTPStatus.BAD_REQUEST | ||
except BusinessException as err: | ||
return err.error, HTTPStatus.CONFLICT | ||
|
||
|
||
@cors_preflight('GET, DELETE, PATCH, OPTIONS') | ||
@API.route('/<int:engagement_translation_id>') | ||
class EngagementTranslation(Resource): | ||
"""Resource for managing engagement translations.""" | ||
|
||
@staticmethod | ||
@cross_origin(origins=allowedorigins()) | ||
# pylint: disable=unused-argument | ||
def get(engagement_id, engagement_translation_id): | ||
"""Fetch a engagement translation by id.""" | ||
try: | ||
engagement_translation = ( | ||
EngagementTranslationService.get_engagement_translation_by_id( | ||
engagement_translation_id | ||
) | ||
) | ||
return ( | ||
EngagementTranslationSchema().dump(engagement_translation), | ||
HTTPStatus.OK, | ||
) | ||
except (KeyError, ValueError) as err: | ||
return str(err), HTTPStatus.INTERNAL_SERVER_ERROR | ||
|
||
@staticmethod | ||
@cross_origin(origins=allowedorigins()) | ||
@_jwt.requires_auth | ||
def delete(engagement_id, engagement_translation_id): | ||
"""Remove engagement translation.""" | ||
try: | ||
EngagementTranslationService().delete_engagement_translation(engagement_id, | ||
engagement_translation_id) | ||
return 'Engagement translation successfully removed', HTTPStatus.OK | ||
except KeyError as err: | ||
return str(err), HTTPStatus.BAD_REQUEST | ||
except ValueError as err: | ||
return str(err), HTTPStatus.NOT_FOUND | ||
|
||
@staticmethod | ||
@cross_origin(origins=allowedorigins()) | ||
@_jwt.requires_auth | ||
def patch(engagement_id, engagement_translation_id): | ||
"""Update engagement translation.""" | ||
try: | ||
translation_data = request.get_json() | ||
updated_engagement = EngagementTranslationService().update_engagement_translation( | ||
engagement_id, engagement_translation_id, translation_data) | ||
return updated_engagement, HTTPStatus.OK | ||
except ValueError as err: | ||
return str(err), HTTPStatus.NOT_FOUND | ||
except ValidationError as err: | ||
return str(err.messages), HTTPStatus.BAD_REQUEST |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
"""Engagement translation schema class.""" | ||
|
||
from marshmallow import EXCLUDE, Schema, fields | ||
|
||
|
||
class EngagementTranslationSchema(Schema): | ||
"""Engagement translation schema.""" | ||
|
||
class Meta: # pylint: disable=too-few-public-methods | ||
"""Exclude unknown fields in the deserialized output.""" | ||
|
||
unknown = EXCLUDE | ||
|
||
id = fields.Int(data_key='id') | ||
engagement_id = fields.Int(data_key='engagement_id', required=True) | ||
language_id = fields.Int(data_key='language_id', required=True) | ||
name = fields.Str(data_key='name') | ||
description = fields.Str(data_key='description') | ||
rich_description = fields.Str(data_key='rich_description') | ||
content = fields.Str(data_key='content') | ||
rich_content = fields.Str(data_key='rich_content') | ||
consent_message = fields.Str(data_key='consent_message') | ||
slug = fields.Str(data_key='slug') | ||
upcoming_status_block_text = fields.Str(data_key='upcoming_status_block_text') | ||
open_status_block_text = fields.Str(data_key='open_status_block_text') | ||
closed_status_block_text = fields.Str(data_key='closed_status_block_text') |
31 changes: 31 additions & 0 deletions
31
met-api/src/met_api/schemas/schemas/engagement_translation.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
{ | ||
"$schema": "http://json-schema.org/draft-07/schema", | ||
"$id": "https://met.gov.bc.ca/.well_known/schemas/engagement_translation", | ||
"type": "object", | ||
"title": "The root schema", | ||
"description": "The root schema comprises the entire JSON document.", | ||
"default": {}, | ||
"examples": [ | ||
{ | ||
"engagement_id": 1, | ||
"language_id": 1 | ||
} | ||
], | ||
"required": ["engagement_id", "language_id"], | ||
"properties": { | ||
"engagement_id": { | ||
"$id": "#/properties/engagement_id", | ||
"type": "number", | ||
"title": "engagement id", | ||
"description": "The engagement to which this translation belongs.", | ||
"examples": [1] | ||
}, | ||
"language_id": { | ||
"$id": "#/properties/language_id", | ||
"type": "number", | ||
"title": "Language id", | ||
"description": "The language to which this translation belongs.", | ||
"examples": [1] | ||
} | ||
} | ||
} |
Oops, something went wrong.