Skip to content

Commit

Permalink
Merge pull request #2216 from auslin-aot/feature/FWF-3581-add-major-m…
Browse files Browse the repository at this point in the history
…inor-versions-to-form-history

❇️ FWF-3581: [Feature] Add major and minor versions to form versioning
  • Loading branch information
arun-s-aot authored Sep 2, 2024
2 parents d209759 + ecd3a96 commit cb02aca
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""Script to update existing form history records by inserting values
into the major_version and minor_version columns.
Revision ID: 9929f234cef0
Revises: ae48e890f2e2
Create Date: 2024-08-28 16:49:12.699755
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '9929f234cef0'
down_revision = 'ae48e890f2e2'
branch_labels = None
depends_on = None


def upgrade():
conn = op.get_bind()
# Get distinct parent_form_ids
distinct_parent_ids = conn.execute(sa.text(
"SELECT DISTINCT parent_form_id FROM form_history")).fetchall()

for parent_id in distinct_parent_ids:
# Get all rows for this parent_form_id in ascending order by id
stmt = "SELECT id, change_log FROM form_history WHERE parent_form_id = :parent_id ORDER BY id ASC"
rows = conn.execute(sa.text(stmt), {"parent_id": parent_id[0]}).mappings().all()

previous_version = None

for row in rows:
change_log = row['change_log']
current_version = change_log.get('version')

if current_version:
major_version = int(current_version.strip('v'))
previous_version = major_version
else:
major_version = previous_version

if major_version is not None:
update_stmt ="UPDATE form_history SET minor_version=0, major_version = :major_version WHERE id = :id"
conn.execute(sa.text(update_stmt), {"major_version": major_version, "id": row['id']})


def downgrade():
# Add downgrade logic if necessary
pass

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Added major & minor version columns to form history table.
Revision ID: ae48e890f2e2
Revises: b0ecd447cfa5
Create Date: 2024-08-28 11:29:41.480868
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'ae48e890f2e2'
down_revision = 'b0ecd447cfa5'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('form_history', sa.Column('major_version', sa.Integer(), nullable=True))
op.add_column('form_history', sa.Column('minor_version', sa.Integer(), nullable=True))
op.create_index(op.f('ix_form_history_major_version'), 'form_history', ['major_version'], unique=False)
op.create_index(op.f('ix_form_history_minor_version'), 'form_history', ['minor_version'], unique=False)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_form_history_minor_version'), table_name='form_history')
op.drop_index(op.f('ix_form_history_major_version'), table_name='form_history')
op.drop_column('form_history', 'minor_version')
op.drop_column('form_history', 'major_version')
# ### end Alembic commands ###
27 changes: 7 additions & 20 deletions forms-flow-api/src/formsflow_api/models/form_history_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from typing import List

from sqlalchemy import JSON, and_, desc, text
from sqlalchemy import JSON, and_, desc

from formsflow_api.models.base_model import BaseModel
from formsflow_api.models.db import db
Expand All @@ -24,6 +24,8 @@ class FormHistory(ApplicationAuditDateTimeMixin, BaseModel, db.Model):
anonymous = db.Column(db.Boolean, nullable=True)
status = db.Column(db.Boolean, nullable=True)
form_type = db.Column(db.Boolean, nullable=True)
major_version = db.Column(db.Integer, index=True)
minor_version = db.Column(db.Integer, index=True)

@classmethod
def create_history(cls, data) -> "FormHistory":
Expand All @@ -41,6 +43,8 @@ def create_history(cls, data) -> "FormHistory":
history.component_change = data.get("component_change")
history.anonymous = data.get("anonymous")
history.status = data.get("status")
history.major_version = data.get("major_version")
history.minor_version = data.get("minor_version")
history.save()
return history
return None
Expand All @@ -57,28 +61,11 @@ def fetch_histories_by_parent_id(cls, parent_id) -> List["FormHistory"]:
.all()
)

@classmethod
def get_version_count(cls, parent_form_id):
"""Get count of form versions."""
return cls.query.filter(
and_(
cls.parent_form_id == parent_form_id,
cls.component_change.is_(True),
text("CAST(change_log->>'new_version' AS BOOLEAN) = true"),
)
).count()

@classmethod
def get_latest_version(cls, parent_form_id):
"""Get latest version number."""
return (
cls.query.filter(
and_(
cls.parent_form_id == parent_form_id,
cls.component_change.is_(True),
text("CAST(change_log->>'new_version' AS BOOLEAN) = true"),
)
)
.order_by(desc(FormHistory.id))
cls.query.filter(cls.parent_form_id == parent_form_id)
.order_by(cls.major_version.desc(), cls.minor_version.desc())
.first()
)
9 changes: 9 additions & 0 deletions forms-flow-api/src/formsflow_api/schemas/form_history_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,12 @@ class Meta: # pylint: disable=too-few-public-methods
created_by = fields.Str(data_key="createdBy")
created = fields.Str(data_key="created")
change_log = fields.Dict(data_key="changeLog")
major_version = fields.Int(data_key="majorVersion")
minor_version = fields.Int(data_key="minorVersion")
version = fields.Method("get_combined_version", dump_only=True)

def get_combined_version(self, obj):
"""Combine major and minor versions."""
major_version = obj.major_version or 1
minor_version = obj.minor_version or 0
return f"{major_version}.{minor_version}"
26 changes: 15 additions & 11 deletions forms-flow-api/src/formsflow_api/services/form_history_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,16 @@ def create_form_log_with_clone(data, **kwargs):
response = formio_service.create_form(data, form_io_token)
# Version details is used set version number
version_data_schema = FormHistorySchema()
version_data = FormHistory.get_latest_version(parent_form_id)
major_version, minor_version = 0, 0
if version_data:
major_version = version_data.major_version
minor_version = version_data.minor_version
if data.get("newVersion") is True:
version_number = "v" + str(
FormHistory.get_version_count(parent_form_id) + 1
)
major_version += 1
minor_version = 0
else:
version_data = version_data_schema.dump(
FormHistory.get_latest_version(parent_form_id)
)
version_number = (
version_data.get("changeLog")
and version_data.get("changeLog").get("version")
) or None
minor_version += 1
# Form history data to save into form history table
form_history_data = {
"form_id": form_id,
Expand All @@ -60,8 +58,9 @@ def create_form_log_with_clone(data, **kwargs):
"change_log": {
"cloned_form_id": response.get("_id"),
"new_version": data.get("newVersion") or False,
"version": version_number,
},
"major_version": major_version,
"minor_version": minor_version,
}
create_form_history = FormHistory.create_history(form_history_data)
return version_data_schema.dump(create_form_history)
Expand Down Expand Up @@ -94,6 +93,11 @@ def create_form_logs_without_clone(data, **kwargs):
form_logs_data["created_by"] = user_name
form_logs_data["form_id"] = data.get("formId")
form_logs_data["parent_form_id"] = data.get("parentFormId")
# Capture version details in form history
version_data = FormHistory.get_latest_version(data.get("parentFormId"))
if version_data:
form_logs_data["major_version"] = version_data.major_version
form_logs_data["minor_version"] = version_data.minor_version
history_schema = FormHistorySchema()
create_form_history = FormHistory.create_history(form_logs_data)
return history_schema.dump(create_form_history)
Expand Down
43 changes: 43 additions & 0 deletions forms-flow-api/tests/unit/api/test_form_process_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from unittest.mock import MagicMock
import pytest
from formsflow_api.models import FormProcessMapper
from formsflow_api.services import FormHistoryService
from formsflow_api_utils.utils import (
ADMIN,
CREATE_DESIGNS,
Expand Down Expand Up @@ -525,3 +526,45 @@ def test_export(app, client, session, jwt, mock_redis_client):
# assert len(response.json["workflows"]) == 3
# assert len(response.json["rules"]) == 0
# assert len(response.json["authorizations"]) == 1


def test_form_history(app, client, session, jwt, mock_redis_client):
"""Testing form history."""
token = get_token(jwt, role=CREATE_DESIGNS, username="designer")
headers = {"Authorization": f"Bearer {token}", "content-type": "application/json"}
payload = get_formio_form_request_payload()
payload["componentChanged"] = True
payload["newVersion"] = True
response = client.post(
"/form/form-design", headers=headers, json=payload
)
assert response.status_code == 201
form_id = response.json["_id"]
# Assert form history with major version
response = client.get(f"/form/form-history/{form_id}", headers=headers)
assert response.status_code == 200
assert response.json is not None
assert len(response.json) == 1
assert response.json[0]["majorVersion"] == 1
assert response.json[0]["minorVersion"] == 0
assert response.json[0]["formId"] == form_id
assert response.json[0]["version"] == "1.0"

# Assert form history with minor version
update_payload = get_formio_form_request_payload()
update_payload["componentChanged"] = True
update_payload["parentFormId"] = form_id
update_payload["_id"] = form_id
FormHistoryService.create_form_log_with_clone(data=update_payload)
response = client.get(f"/form/form-history/{form_id}", headers=headers)
assert response.status_code == 200
assert response.json is not None
assert len(response.json) == 2
assert response.json[0]["majorVersion"] == 1
assert response.json[0]["minorVersion"] == 1
assert response.json[0]["formId"] == form_id
assert response.json[0]["version"] == "1.1"
assert response.json[1]["majorVersion"] == 1
assert response.json[1]["minorVersion"] == 0
assert response.json[1]["formId"] == form_id
assert response.json[1]["version"] == "1.0"
4 changes: 2 additions & 2 deletions forms-flow-web/src/components/Form/Item/FormHistoryModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ const FormHistoryModal = ({ historyModal, handleModalChange, gotoEdit }) => {
formHistory.length > 1 && (
<span className="text-primary">{
history.changeLog?.new_version ?
t(history.changeLog?.version ? `Version ${history.changeLog.version} created` : "New version created") :
t(history.changeLog.version ? `Version ${history.changeLog.version}` : "")}
t(history.version ? `Version ${history.version} created` : "New version created") :
t(history.version ? `Version ${history.version}` : "")}
</span>
)
}
Expand Down

0 comments on commit cb02aca

Please sign in to comment.