Skip to content

Commit 1da3693

Browse files
nnhathungHieu Lam - TMAlthanhhieumariobehling
authored
feature-8958: Store check in kiosk id to mark association (#8991)
* feature-8958: Store check in kiosk id to mark association * feature-8958: Store check in kiosk id to mark association * feature-8958: Store check in kiosk id to mark association set validate for station type and station name * feature-8958: Store check in kiosk id to mark association fix ci/cd * feature-8958: Store check in kiosk id to mark association fix ci and update latest branch from development * feature-8958: Store check in kiosk id to mark association fix ci and update latest branch from development * feature-8958: Store check in kiosk id to mark association fix ci and update latest branch from development * feature-8958: Store check in kiosk id to mark association fix ci and update latest branch from development * feature-8958: Store check in kiosk id to mark association fix ci and update latest branch from development * feature-8958: Store check in kiosk id to mark association fix ci and update latest branch from development * feature-8958: Store check in kiosk id to mark association * feature-8958: Store check in kiosk id to mark association update station_type, remove session, add new 2 types check in and check out * feature-8958: Store check in kiosk id to mark association * feature-8958: Store check in kiosk id to mark association * fix multiple migration head * fix alembic revision --------- Co-authored-by: Hieu Lam - TMA <[email protected]> Co-authored-by: lthanhhieu <[email protected]> Co-authored-by: Mario Behling <[email protected]>
1 parent 07f10f1 commit 1da3693

File tree

8 files changed

+325
-1
lines changed

8 files changed

+325
-1
lines changed

app/api/helpers/static.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,3 +573,5 @@
573573
]
574574

575575
LEVEL_CHOICES = ['Beginner', 'Intermediate', 'Advanced', 'Expert']
576+
577+
STATION_CHOICES = ['registration', 'daily', 'check in', 'check out']

app/api/routes.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,12 @@
225225
SponsorListPost,
226226
SponsorRelationship,
227227
)
228+
from app.api.station import (
229+
StationDetail,
230+
StationList,
231+
StationListPost,
232+
StationRelationship,
233+
)
228234
from app.api.stripe_authorization import (
229235
StripeAuthorizationDetail,
230236
StripeAuthorizationListPost,
@@ -815,6 +821,7 @@
815821
'/users-events-roles/<int:users_events_roles_id>/event',
816822
'/exhibitors/<int:exhibitor_id>/event',
817823
'/speaker-invites/<int:speaker_invite_id>/event',
824+
'/stations/<int:station_id>/event',
818825
'/badge-forms/<int:badge_form_id>/event',
819826
)
820827
api.route(
@@ -1052,6 +1059,12 @@
10521059
'/events/<int:id>/relationships/speaker-invites',
10531060
'/events/<identifier>/relationships/speaker-invites',
10541061
)
1062+
api.route(
1063+
EventRelationship,
1064+
'station',
1065+
'/events/<int:id>/relationships/station',
1066+
'/events/<identifier>/relationships/stations',
1067+
)
10551068

10561069
# microlocations
10571070
api.route(MicrolocationListPost, 'microlocation_list_post', '/microlocations')
@@ -1067,6 +1080,7 @@
10671080
'microlocation_detail',
10681081
'/microlocations/<int:id>',
10691082
'/sessions/<int:session_id>/microlocation',
1083+
'/stations/<int:station_id>/microlocation',
10701084
)
10711085
api.route(
10721086
MicrolocationRelationshipOptional,
@@ -2008,6 +2022,30 @@
20082022
'custom_form_translate_form',
20092023
'/custom-form-translates/<int:id>/relationships/custom-form',
20102024
)
2025+
# station
2026+
api.route(
2027+
StationListPost,
2028+
'station_list_post',
2029+
'/station',
2030+
)
2031+
api.route(
2032+
StationList,
2033+
'station_list',
2034+
'/events/<int:event_id>/stations',
2035+
'/events/<event_identifier>/stations',
2036+
'/microlocations/<int:microlocation_id>/stations',
2037+
)
2038+
api.route(StationDetail, 'station_detail', '/stations/<int:id>')
2039+
api.route(
2040+
StationRelationship,
2041+
'station_event',
2042+
'/stations/<int:id>/relationships/event',
2043+
)
2044+
api.route(
2045+
StationRelationship,
2046+
'station_microlocation',
2047+
'/stations/<int:id>/relationships/microlocation',
2048+
)
20112049
api.route(
20122050
BadgeFormListPost,
20132051
'badge_form_list_post',

app/api/schema/events.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,15 @@ def validate_timezone(self, data, original_data):
385385
type_='speaker-invite',
386386
many=True,
387387
)
388+
station = Relationship(
389+
self_view='v1.station',
390+
self_view_kwargs={'id': '<id>'},
391+
related_view='v1.station_list',
392+
related_view_kwargs={'event_id': '<id>'},
393+
schema='StationSchema',
394+
type_='station',
395+
many=True,
396+
)
388397
badge_forms = Relationship(
389398
attribute='badge_form',
390399
self_view='v1.event_badge_forms',

app/api/schema/station.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from marshmallow import validate
2+
from marshmallow_jsonapi import fields
3+
from marshmallow_jsonapi.flask import Relationship, Schema
4+
5+
from app.api.helpers.static import STATION_CHOICES
6+
from app.api.helpers.utilities import dasherize
7+
from utils.common import use_defaults
8+
9+
10+
@use_defaults()
11+
class StationSchema(Schema):
12+
"""API Schema for Station database model"""
13+
14+
class Meta:
15+
"""Meta class for Station Schema"""
16+
17+
type_ = 'station'
18+
self_view = 'v1.station_detail'
19+
self_view_kwargs = {'id': '<id>'}
20+
inflect = dasherize
21+
22+
id = fields.Integer(dump_only=True)
23+
station_name = fields.String(required=True, validate=validate.Length(min=1))
24+
station_type = fields.String(required=True,
25+
validate=validate.OneOf(choices=STATION_CHOICES))
26+
microlocation_id = fields.Function(lambda obj: obj.microlocation.id)
27+
28+
room = fields.Function(lambda obj: obj.microlocation.room)
29+
event = Relationship(
30+
self_view='v1.station_event',
31+
self_view_kwargs={'id': '<id>'},
32+
related_view='v1.event_detail',
33+
related_view_kwargs={'id': '<id>'},
34+
schema='EventSchemaPublic',
35+
type_='event',
36+
)
37+
microlocation = Relationship(
38+
self_view='v1.station_microlocation',
39+
self_view_kwargs={'id': '<id>'},
40+
related_view='v1.microlocation_detail',
41+
related_view_kwargs={'id': '<microlocation_id>'},
42+
schema='MicrolocationSchema',
43+
type_='microlocation',
44+
)

app/api/station.py

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
from flask_rest_jsonapi import ResourceDetail, ResourceList, ResourceRelationship
2+
from flask_rest_jsonapi.exceptions import ObjectNotFound
3+
4+
from app.api.helpers.db import safe_query_kwargs
5+
from app.api.helpers.errors import UnprocessableEntityError
6+
from app.api.helpers.permission_manager import has_access
7+
from app.api.helpers.permissions import jwt_required
8+
from app.api.helpers.utilities import require_relationship
9+
from app.api.schema.station import StationSchema
10+
from app.models import db
11+
from app.models.event import Event
12+
from app.models.microlocation import Microlocation
13+
from app.models.station import Station
14+
15+
16+
class StationList(ResourceList):
17+
"""Create and List Station"""
18+
19+
def query(self, view_kwargs):
20+
"""
21+
query method for different view_kwargs
22+
:param view_kwargs:
23+
:return:
24+
"""
25+
query_ = self.session.query(Station)
26+
if view_kwargs.get('event_id'):
27+
event = safe_query_kwargs(Event, view_kwargs, 'event_id')
28+
query_ = query_.filter_by(event_id=event.id)
29+
30+
elif view_kwargs.get('microlocation_id'):
31+
event = safe_query_kwargs(Microlocation, view_kwargs, 'microlocation_id')
32+
query_ = query_.filter_by(microlocation_id=event.id)
33+
34+
return query_
35+
36+
view_kwargs = True
37+
schema = StationSchema
38+
data_layer = {
39+
'session': db.session,
40+
'model': Station,
41+
'methods': {'query': query},
42+
}
43+
44+
45+
class StationDetail(ResourceDetail):
46+
"""Station detail by id"""
47+
48+
@staticmethod
49+
def before_patch(args, kwargs, data):
50+
"""
51+
before patch method
52+
:param args:
53+
:param kwargs:
54+
:param data:
55+
:return:
56+
"""
57+
require_relationship(['event'], data)
58+
if not has_access('is_coorganizer', event=data['event']):
59+
raise ObjectNotFound(
60+
{'parameter': 'event'},
61+
f"Event: {data['event']} not found {args} {kwargs}",
62+
)
63+
64+
if data.get('microlocation'):
65+
require_relationship(['microlocation'], data)
66+
if not has_access('is_coorganizer', microlocation=data['microlocation']):
67+
raise ObjectNotFound(
68+
{'parameter': 'microlocation'},
69+
f"Microlocation: {data['microlocation']} not found",
70+
)
71+
else:
72+
if data['station_type'] in ('check in', 'check out', 'daily'):
73+
raise ObjectNotFound(
74+
{'parameter': 'microlocation'},
75+
"Microlocation: microlocation_id is missing from your request.",
76+
)
77+
station = Station.query.filter_by(
78+
station_type=data.get('station_type'),
79+
microlocation_id=data.get('microlocation'),
80+
event_id=data.get('event'),
81+
).first()
82+
if station:
83+
raise UnprocessableEntityError(
84+
{
85+
'station_type': data.get('station_type'),
86+
'microlocation_id': data.get('microlocation'),
87+
'event_id': data.get('event'),
88+
},
89+
"A Station already exists for the provided Event ID"
90+
", Microlocation ID and Station type",
91+
)
92+
93+
schema = StationSchema
94+
data_layer = {
95+
'session': db.session,
96+
'model': Station,
97+
}
98+
99+
100+
class StationRelationship(ResourceRelationship):
101+
"""Station Relationship (Required)"""
102+
103+
decorators = (jwt_required,)
104+
methods = ['GET', 'PATCH']
105+
schema = StationSchema
106+
data_layer = {'session': db.session, 'model': Station}
107+
108+
109+
class StationListPost(ResourceList):
110+
"""Create and List Station"""
111+
112+
@staticmethod
113+
def before_post(args, kwargs, data):
114+
"""
115+
method to check for required relationship with event and microlocation
116+
:param data:
117+
:param args:
118+
:param kwargs:
119+
:return:
120+
"""
121+
require_relationship(['event'], data)
122+
if not has_access('is_coorganizer', event=data['event']):
123+
raise ObjectNotFound(
124+
{'parameter': 'event'},
125+
f"Event: {data['event']} not found {args} {kwargs}",
126+
)
127+
128+
if data.get('microlocation'):
129+
require_relationship(['microlocation'], data)
130+
if not has_access('is_coorganizer', microlocation=data['microlocation']):
131+
raise ObjectNotFound(
132+
{'parameter': 'microlocation'},
133+
f"Microlocation: {data['microlocation']} not found",
134+
)
135+
else:
136+
if data['station_type'] in ('check in', 'check out', 'daily'):
137+
raise ObjectNotFound(
138+
{'parameter': 'microlocation'},
139+
"Microlocation: missing from your request.",
140+
)
141+
142+
def before_create_object(self, data, view_kwargs):
143+
"""
144+
function to check if station already exist
145+
@param data:
146+
@param view_kwargs:
147+
"""
148+
station = (
149+
self.session.query(Station)
150+
.filter_by(
151+
station_type=data.get('station_type'),
152+
microlocation_id=data.get('microlocation'),
153+
event_id=data.get('event'),
154+
)
155+
.first()
156+
)
157+
if station:
158+
raise UnprocessableEntityError(
159+
{
160+
'station_type': data.get('station_type'),
161+
'microlocation_id': data.get('microlocation'),
162+
'event_id': data.get('event'),
163+
'view_kwargs': view_kwargs,
164+
},
165+
"A Station already exists for the provided Event ID"
166+
", Microlocation ID and Station type",
167+
)
168+
169+
schema = StationSchema
170+
methods = [
171+
'POST',
172+
]
173+
data_layer = {
174+
'session': db.session,
175+
'model': Station,
176+
'methods': {'before_create_object': before_create_object},
177+
}

app/models/station.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from app.models import db
2+
3+
4+
class Station(db.Model):
5+
"""Station database model"""
6+
7+
id = db.Column(db.Integer, primary_key=True)
8+
station_name = db.Column(db.String, nullable=False)
9+
station_type = db.Column(db.String, nullable=True)
10+
microlocation_id = db.Column(db.Integer, db.ForeignKey('microlocations.id',
11+
ondelete='CASCADE'))
12+
microlocation = db.relationship('Microlocation', backref='stations',
13+
foreign_keys=[microlocation_id])
14+
event_id = db.Column(db.Integer, db.ForeignKey('events.id', ondelete='CASCADE'))
15+
event = db.relationship('Event', backref='stations', foreign_keys=[event_id])
16+
17+
def __repr__(self):
18+
return f'<Station {self.id}>'
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""empty message
2+
3+
Revision ID: 9881f067213b
4+
Revises: f508644acbd3
5+
Create Date: 2023-07-18 18:29:35.835886
6+
7+
"""
8+
9+
from alembic import op
10+
import sqlalchemy as sa
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = '9881f067213b'
15+
down_revision = '2b19596af9f0'
16+
17+
18+
def upgrade():
19+
# ### commands auto generated by Alembic - please adjust! ###
20+
op.create_table('station',
21+
sa.Column('id', sa.Integer(), nullable=False),
22+
sa.Column('station_name', sa.String(), nullable=False),
23+
sa.Column('station_type', sa.String(), nullable=True),
24+
sa.Column('microlocation_id', sa.Integer(), nullable=True),
25+
sa.Column('event_id', sa.Integer(), nullable=True),
26+
sa.ForeignKeyConstraint(['event_id'], ['events.id'], ondelete='CASCADE'),
27+
sa.ForeignKeyConstraint(['microlocation_id'], ['microlocations.id'], ondelete='CASCADE'),
28+
sa.PrimaryKeyConstraint('id')
29+
)
30+
# ### end Alembic commands ###
31+
32+
33+
def downgrade():
34+
# ### commands auto generated by Alembic - please adjust! ###
35+
op.drop_table('station')
36+
# ### end Alembic commands ###

migrations/versions/rev-2023-07-19-10:01:32-3b784f9c98c7_.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
# revision identifiers, used by Alembic.
1313
revision = '3b784f9c98c7'
14-
down_revision = '2b19596af9f0'
14+
down_revision = '9881f067213b'
1515

1616

1717
def upgrade():

0 commit comments

Comments
 (0)