-
Notifications
You must be signed in to change notification settings - Fork 19
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
Deseng-463:Poll Widget: Back-end #2363
Merged
Merged
Changes from 14 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
a1c163b
DESENG-463: Created models for Poll widget
ratheesh-aot e4b3842
DESENG-463: Resources, Services and Schema
ratheesh-aot 3bd9364
DESENG-463: Wrapping up API changes
ratheesh-aot a9ff2f7
Merge remote-tracking branch 'upstream/main' into DESENG-463-POLL
ratheesh-aot badb457
DESENG-463: Refactoring
ratheesh-aot 6fba5d1
DESENG-463: Poll API updates
ratheesh-aot 35aa0ef
DESENG-463 : Updated logics
ratheesh-aot 86a3f64
DESENG-463 : Written unit test cases
ratheesh-aot f3f5554
Updated Change log
ratheesh-aot ab7b322
Solved pylint issues
ratheesh-aot 4f64cd5
fixing flake8 comments
ratheesh-aot 80b8fd4
Merge remote-tracking branch 'upstream/main' into DESENG-463-POLL
ratheesh-aot 17d2dc8
Fixing lint issues
ratheesh-aot 8d9c9d4
Fixing sonarcloud suggestions
ratheesh-aot 58d1f33
DESENG-463: Fixing Review comments
ratheesh-aot 76cff56
Fixing lint
ratheesh-aot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
83 changes: 83 additions & 0 deletions
83
met-api/migrations/versions/08f69642b7ae_adding_widget_poll.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,83 @@ | ||
"""adding_widget_poll | ||
|
||
Revision ID: 08f69642b7ae | ||
Revises: bd0eb0d25caf | ||
Create Date: 2024-01-16 14:25:07.611485 | ||
|
||
""" | ||
from alembic import op | ||
import sqlalchemy as sa | ||
from sqlalchemy.dialects import postgresql | ||
|
||
# revision identifiers, used by Alembic. | ||
revision = '08f69642b7ae' | ||
down_revision = 'bd0eb0d25caf' | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade(): | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.create_table('widget_polls', | ||
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('title', sa.String(length=255), nullable=False), | ||
sa.Column('description', sa.String(length=2048), nullable=True), | ||
sa.Column('status', sa.Enum('active', 'inactive', name='poll_status'), nullable=True), | ||
sa.Column('widget_id', sa.Integer(), nullable=False), | ||
sa.Column('engagement_id', sa.Integer(), nullable=False), | ||
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(['widget_id'], ['widget.id'], ondelete='CASCADE'), | ||
sa.PrimaryKeyConstraint('id') | ||
) | ||
op.create_table('poll_answers', | ||
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('answer_text', sa.String(length=255), nullable=False), | ||
sa.Column('poll_id', sa.Integer(), nullable=False), | ||
sa.Column('created_by', sa.String(length=50), nullable=True), | ||
sa.Column('updated_by', sa.String(length=50), nullable=True), | ||
sa.ForeignKeyConstraint(['poll_id'], ['widget_polls.id'], ondelete='CASCADE'), | ||
sa.PrimaryKeyConstraint('id') | ||
) | ||
op.create_table('poll_responses', | ||
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('participant_id', sa.String(length=255), nullable=False), | ||
sa.Column('selected_answer_id', sa.Integer(), nullable=False), | ||
sa.Column('poll_id', sa.Integer(), nullable=False), | ||
sa.Column('widget_id', sa.Integer(), nullable=False), | ||
sa.Column('is_deleted', sa.Boolean(), nullable=True), | ||
sa.Column('created_by', sa.String(length=50), nullable=True), | ||
sa.Column('updated_by', sa.String(length=50), nullable=True), | ||
sa.ForeignKeyConstraint(['poll_id'], ['widget_polls.id'], ondelete='CASCADE'), | ||
sa.ForeignKeyConstraint(['selected_answer_id'], ['poll_answers.id'], ondelete='CASCADE'), | ||
sa.ForeignKeyConstraint(['widget_id'], ['widget.id'], ondelete='CASCADE'), | ||
sa.PrimaryKeyConstraint('id') | ||
) | ||
widget_type_table = sa.table('widget_type', | ||
sa.Column('id', sa.Integer), | ||
sa.Column('name', sa.String), | ||
sa.Column('description', sa.String)) | ||
|
||
op.bulk_insert(widget_type_table, [ | ||
{'id': 10, 'name': 'Poll', 'description': 'The Poll Widget enables real-time polling and feedback collection from public.'} | ||
]) | ||
# ### end Alembic commands ### | ||
|
||
|
||
def downgrade(): | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.drop_table('poll_responses') | ||
op.drop_table('poll_answers') | ||
op.drop_table('widget_polls') | ||
|
||
conn = op.get_bind() | ||
|
||
conn.execute('DELETE FROM widget_type WHERE id=10') | ||
# ### 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,56 @@ | ||
""" | ||
PollAnswers model class. | ||
|
||
Manages the Poll answers | ||
""" | ||
from __future__ import annotations | ||
|
||
from sqlalchemy.sql.schema import ForeignKey | ||
|
||
from .base_model import BaseModel | ||
from .db import db | ||
|
||
|
||
class PollAnswer(BaseModel): | ||
"""Definition of the PollAnswer entity.""" | ||
|
||
__tablename__ = 'poll_answers' | ||
id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
answer_text = db.Column(db.String(255), nullable=False) | ||
poll_id = db.Column(db.Integer, ForeignKey('widget_polls.id', | ||
ondelete='CASCADE'), nullable=False) | ||
|
||
@classmethod | ||
def get_answers(cls, poll_id) -> list[PollAnswer]: | ||
"""Get answers for a poll.""" | ||
session = db.session.query(PollAnswer) | ||
return session.filter(PollAnswer.poll_id == poll_id).all() | ||
|
||
@classmethod | ||
def update_answer(cls, answer_id, answer_data: dict) -> PollAnswer: | ||
"""Update an answer.""" | ||
answer = PollAnswer.query.get(answer_id) | ||
if answer: | ||
for key, value in answer_data.items(): | ||
setattr(answer, key, value) | ||
answer.save() | ||
return answer | ||
|
||
@classmethod | ||
def delete_answers_by_poll_id(cls, poll_id): | ||
"""Delete answers.""" | ||
poll_answers = db.session.query(PollAnswer).filter( | ||
PollAnswer.poll_id == poll_id | ||
) | ||
poll_answers.delete() | ||
db.session.commit() | ||
|
||
@classmethod | ||
def bulk_insert_answers(cls, poll_id, answers): | ||
"""Bulk insert answers for a poll.""" | ||
answer_data = [ | ||
{'poll_id': poll_id, 'answer_text': answer['answer_text']} | ||
for answer in answers | ||
] | ||
db.session.bulk_insert_mappings(PollAnswer, answer_data) | ||
db.session.commit() |
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,46 @@ | ||
""" | ||
PollResponse model class. | ||
|
||
Manages the Poll Responses | ||
""" | ||
from __future__ import annotations | ||
|
||
from sqlalchemy.sql.expression import false | ||
from sqlalchemy.sql.schema import ForeignKey | ||
|
||
from .base_model import BaseModel | ||
from .db import db | ||
|
||
|
||
class PollResponse(BaseModel): | ||
"""Definition of the PollResponse entity.""" | ||
|
||
__tablename__ = 'poll_responses' | ||
id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
participant_id = db.Column(db.String(255), nullable=False) | ||
selected_answer_id = db.Column(db.Integer, ForeignKey('poll_answers.id', ondelete='CASCADE'), nullable=False) | ||
poll_id = db.Column(db.Integer, ForeignKey('widget_polls.id', ondelete='CASCADE'), nullable=False) | ||
widget_id = db.Column(db.Integer, ForeignKey('widget.id', ondelete='CASCADE'), nullable=False) | ||
is_deleted = db.Column(db.Boolean, default=False) | ||
|
||
@classmethod | ||
def get_responses(cls, poll_id) -> list[PollResponse]: | ||
"""Get responses for a poll.""" | ||
return db.session.query(PollResponse).filter(PollResponse.poll_id == poll_id).all() | ||
|
||
@classmethod | ||
def get_responses_by_participant_id(cls, poll_id, participant_id) -> list[PollResponse]: | ||
"""Get responses for a poll.""" | ||
return db.session.query(PollResponse).filter(PollResponse.poll_id == poll_id, | ||
PollResponse.participant_id == participant_id, | ||
PollResponse.is_deleted == false()).all() | ||
|
||
@classmethod | ||
def update_response(cls, response_id, response_data: dict) -> PollResponse: | ||
"""Update a poll response.""" | ||
response = PollResponse.query.get(response_id) | ||
if response: | ||
for key, value in response_data.items(): | ||
setattr(response, key, value) | ||
response.save() | ||
return response |
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,65 @@ | ||
""" | ||
WidgetPoll model class. | ||
|
||
Manages the Poll widget | ||
""" | ||
from __future__ import annotations | ||
|
||
from sqlalchemy import Enum | ||
from sqlalchemy.sql.schema import ForeignKey | ||
|
||
from met_api.models.poll_answers import PollAnswer | ||
|
||
from .base_model import BaseModel | ||
from .db import db | ||
|
||
|
||
class Poll(BaseModel): | ||
"""Definition of the Poll entity.""" | ||
|
||
__tablename__ = 'widget_polls' | ||
id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
title = db.Column(db.String(255), nullable=False) | ||
description = db.Column(db.String(2048), nullable=True) | ||
status = db.Column( | ||
Enum('active', 'inactive', name='poll_status'), default='inactive') | ||
widget_id = db.Column(db.Integer, ForeignKey( | ||
'widget.id', ondelete='CASCADE'), nullable=False) | ||
engagement_id = db.Column(db.Integer, ForeignKey( | ||
'engagement.id', ondelete='CASCADE'), nullable=False) | ||
|
||
# Relationship to timeline_event | ||
answers = db.relationship(PollAnswer, backref='widget_poll', lazy=True) | ||
|
||
@classmethod | ||
def create_poll(cls, widget_id: int, poll_data: dict) -> Poll: | ||
"""Create a new poll.""" | ||
poll = cls() | ||
poll.widget_id = widget_id | ||
poll.title = poll_data.get('title') | ||
poll.description = poll_data.get('description') | ||
poll.status = poll_data.get('status', 'inactive') | ||
poll.engagement_id = poll_data.get('engagement_id') | ||
db.session.add(poll) | ||
db.session.commit() | ||
return poll | ||
|
||
@classmethod | ||
def get_polls(cls, widget_id) -> list[Poll]: | ||
"""Get polls for a widget.""" | ||
return db.session.query(Poll).filter(Poll.widget_id == widget_id).all() | ||
|
||
@classmethod | ||
def update_poll(cls, poll_id, poll_data: dict) -> Poll: | ||
"""Update a poll and its answers.""" | ||
poll: Poll = Poll.query.get(poll_id) | ||
if poll: | ||
# Update poll fields | ||
for key in ['title', 'description', 'status', 'widget_id', | ||
'engagement_id']: | ||
if key in poll_data: | ||
setattr(poll, key, poll_data[key]) | ||
|
||
db.session.commit() | ||
|
||
return poll |
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
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there will be a need to update user responses. Once a user votes, they can't change it. I don't think we need this method