From 2a41ae63d2076b42181e607d4cd77063cc0b7706 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Mon, 10 Jul 2023 17:09:41 +0700 Subject: [PATCH 01/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_field_forms.py | 71 ++++++ app/api/badge_forms.py | 222 ++++++++++++++++++ app/api/custom/schema/badge_form_field.py | 14 ++ app/api/data_layers/BadgeFormLayer.py | 61 +++++ app/api/routes.py | 58 +++++ app/api/schema/badge_field_forms.py | 43 ++++ app/api/schema/badge_forms.py | 35 +++ app/api/schema/tickets.py | 1 + app/models/badge_field_form.py | 62 +++++ app/models/badge_form.py | 16 ++ app/models/ticket.py | 1 + .../rev-2023-07-10-13:58:32-a03aa4fcb471_.py | 62 +++++ 12 files changed, 646 insertions(+) create mode 100644 app/api/badge_field_forms.py create mode 100644 app/api/badge_forms.py create mode 100644 app/api/custom/schema/badge_form_field.py create mode 100644 app/api/data_layers/BadgeFormLayer.py create mode 100644 app/api/schema/badge_field_forms.py create mode 100644 app/api/schema/badge_forms.py create mode 100644 app/models/badge_field_form.py create mode 100644 app/models/badge_form.py create mode 100644 migrations/versions/rev-2023-07-10-13:58:32-a03aa4fcb471_.py diff --git a/app/api/badge_field_forms.py b/app/api/badge_field_forms.py new file mode 100644 index 0000000000..4c55daa125 --- /dev/null +++ b/app/api/badge_field_forms.py @@ -0,0 +1,71 @@ +from flask_rest_jsonapi import ResourceDetail, ResourceList, ResourceRelationship +from flask_rest_jsonapi.exceptions import ObjectNotFound + +from app.api.helpers.permission_manager import has_access +from app.api.helpers.permissions import jwt_required +from app.api.helpers.utilities import require_relationship +from app.api.schema.badge_field_forms import BadgeFieldFormSchema +from app.models import db +from app.models.badge_field_form import BadgeFieldForms + + +class BadgeFieldFormList(ResourceList): + """Create and List Custom Form Translates""" + + def query(self, view_kwargs): + """ + query method for different view_kwargs + :param view_kwargs: + :return: + """ + query_ = self.session.query(BadgeFieldForms) + if view_kwargs.get('badge_form_id'): + query_ = query_.filter(badge_forms_id=view_kwargs['badge_form_id']) + return query_ + + schema = BadgeFieldFormSchema + data_layer = { + 'session': db.session, + 'model': BadgeFieldForms, + 'methods': {'query': query}, + } + + +class BadgeFieldFormDetail(ResourceDetail): + """BadgeFieldForm Resource Detail""" + + schema = BadgeFieldFormSchema + data_layer = {'session': db.session, 'model': BadgeFieldForms} + + +class BadgeFieldFormRelationship(ResourceRelationship): + """BadgeFieldForm Relationship (Required)""" + + decorators = (jwt_required,) + methods = ['GET', 'PATCH'] + schema = BadgeFieldFormSchema + data_layer = {'session': db.session, 'model': BadgeFieldForms} + + +class BadgeFieldFormListPost(ResourceList): + """Create and List Custom Form Translates""" + + @staticmethod + def before_post(data): + """ + method to check for required relationship with event + :param data: + :return: + """ + require_relationship(['badge_form'], data) + if not has_access('is_coorganizer', badge_form=data['badge_form']): + raise ObjectNotFound( + {'parameter': 'badge_form'}, + f"Custom Form: {data['badge_form']} not found", + ) + + schema = BadgeFieldFormSchema + methods = [ + 'POST', + ] + data_layer = {'session': db.session, 'model': BadgeFieldForms} diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py new file mode 100644 index 0000000000..4e2d748a38 --- /dev/null +++ b/app/api/badge_forms.py @@ -0,0 +1,222 @@ +from flask_rest_jsonapi import ResourceDetail, ResourceList, ResourceRelationship +from flask_rest_jsonapi.exceptions import ObjectNotFound + +from app.api.bootstrap import api +from app.api.data_layers.BadgeFormLayer import BadgeFormLayer +from app.api.helpers.db import safe_query, safe_query_kwargs +from app.api.helpers.permission_manager import has_access +from app.api.helpers.permissions import jwt_required +from app.api.helpers.query import event_query +from app.api.helpers.utilities import require_relationship +from app.api.schema.badge_forms import BadgeFormSchema +from app.models import db +from app.models.badge_field_form import BadgeFieldForms +from app.models.badge_form import BadgeForms +from app.models.event import Event + + +class BadgeFormList(ResourceList): + """Create and List Custom Form Translates""" + + def query(self, view_kwargs): + """ + query method for different view_kwargs + :param view_kwargs: + :return: + """ + query_ = self.session.query(BadgeForms) + if view_kwargs.get('badge_id'): + events = safe_query_kwargs(Event, view_kwargs, 'event_id') + query_ = self.session.query(BadgeForms).filter_by(event_id=events.id) + query_ = query_.filter_by(badge_id=view_kwargs.get('badge_id')) + else: + query_ = event_query(query_, view_kwargs) + return query_ + + @staticmethod + def after_get(badge_forms): + """ + query method for different view_kwargs + :param view_kwargs: + :return: + """ + for item in badge_forms['data']: + badgeFields = [] + badgeFieldForms = ( + BadgeFieldForms.query.filter_by(badge_form_id=item['id']) + .filter_by(badge_id=item['attributes']['badge-id']) + .all() + ) + for badgeFieldForm in badgeFieldForms: + badgeFieldForms.append(badgeFieldForm.convert_to_dict()) + item['attributes']['badge_fields'] = badgeFields + return badge_forms + + view_kwargs = True + decorators = (jwt_required,) + methods = [ + 'GET', + ] + schema = BadgeFormSchema + data_layer = { + 'session': db.session, + 'model': BadgeForms, + 'methods': {'query': query}, + } + + +class BadgeFormDetail(ResourceDetail): + """BadgeForm Resource Detail""" + + def before_get_object(self, view_kwargs): + """ + before get method + :param view_kwargs: + :return: + """ + event = None + if view_kwargs.get('event_id'): + event = safe_query_kwargs(Event, view_kwargs, 'event_id') + elif view_kwargs.get('event_identifier'): + event = safe_query_kwargs( + Event, + view_kwargs, + 'event_identifier', + 'identifier', + ) + + if event: + badge_form = safe_query(BadgeForms, 'event_id', event.id, 'event_id') + view_kwargs['id'] = badge_form.id + + @staticmethod + def before_patch(_args, kwargs, data): + """ + before patch method + :param _args: + :param kwargs: + :param data: + :return: + """ + badgeFields = data.get('badge_fields') + if badgeFields: + for badgeField in badgeFields: + badgeFieldForm = None + if 'id' in badgeField: + badgeFieldForm = BadgeFieldForms.check_badge_field_form( + kwargs['id'], badgeField['id'] + ) + if ( + badgeFieldForm is not None + and 'isDeleted' in badgeField + and badgeField['is_deleted'] + ): + db.session.delete(badgeFieldForm) + else: + badgeFieldForm = BadgeFieldForms() + if badgeFieldForm: + badgeFieldForm.badge_id = data['badge_id'] + else: + badgeFieldForm.badge_id = data['form_id'] + badgeFieldForm.badge_form_id = kwargs['id'] + + badgeFieldForm.custom_field = badgeField['custom_field'] + badgeFieldForm.sample_text = badgeField['sample_text'] + badgeFieldForm.font_name = badgeField['font_name'] + badgeFieldForm.font_size = badgeField['font_size'] + badgeFieldForm.font_color = badgeField['font_color'] + badgeFieldForm.font_weight = badgeField['font_weight'] + badgeFieldForm.text_rotation = badgeField['text_rotation'] + badgeFieldForm.text_alignment = badgeField['text_alignment'] + badgeFieldForm.text_type = badgeField['text_type'] + badgeFieldForm.margin_top = badgeField['margin_top'] + badgeFieldForm.margin_bottom = badgeField['margin_bottom'] + badgeFieldForm.margin_left = badgeField['margin_left'] + badgeFieldForm.margin_right = badgeField['margin_right'] + db.session.add(badgeFieldForm) + + @staticmethod + def before_delete(_obj, kwargs): + """ + before delete method + :param _obj: + :param kwargs: + :return: + """ + badgeFieldForm = BadgeFieldForms.query.filter_by(badge_form_id=kwargs['id']).all() + for item in badgeFieldForm: + db.session.delete(item) + + @staticmethod + def after_patch(badge_form): + """ + after patch method + :param badge_form: + :return: + """ + badgeFields = [] + data = badge_form['data'] + attributes = data['attributes'] + if attributes and attributes['is-complex']: + badgeFieldForms = ( + BadgeFieldForms.query.filter_by(badge_form_id=data['id']) + .filter_by(form_id=attributes['form-id']) + .all() + ) + for badgeFieldForm in badgeFieldForms: + badgeFields.append(badgeFieldForm.convert_to_dict()) + attributes['badge_fields'] = badgeFields + return badge_form + + decorators = ( + api.has_permission( + 'is_coorganizer', + fetch='event_id', + model=BadgeForms, + methods="PATCH,DELETE", + ), + ) + schema = BadgeFormSchema + data_layer = { + 'session': db.session, + 'model': BadgeForms, + 'methods': { + 'before_get_object': before_get_object, + 'before_patch': before_patch, + 'before_delete': before_delete, + 'after_patch': after_patch, + }, + } + + +class BadgeFormRelationship(ResourceRelationship): + """BadgeForm Relationship (Required)""" + + decorators = (jwt_required,) + methods = ['GET', 'PATCH'] + schema = BadgeFormSchema + data_layer = {'session': db.session, 'model': BadgeForms} + + +class BadgeFormListPost(ResourceList): + """Create and List Custom Form Translates""" + + def before_post(self, _args, _kwargs, data): + """ + method to check for required relationship with event + :param args: + :param kwargs: + :param data: + :return: + """ + require_relationship(['event'], data) + if not has_access('is_coorganizer', event_id=data['event']): + raise ObjectNotFound( + {'parameter': 'event_id'}, "Event: {} not found".format(data['event_id']) + ) + + schema = BadgeFormSchema + methods = [ + 'POST', + ] + data_layer = {'class': BadgeFormLayer, 'session': db.session, 'model': BadgeForms} diff --git a/app/api/custom/schema/badge_form_field.py b/app/api/custom/schema/badge_form_field.py new file mode 100644 index 0000000000..597a273fc6 --- /dev/null +++ b/app/api/custom/schema/badge_form_field.py @@ -0,0 +1,14 @@ +from marshmallow import Schema, fields + + +class BadgeFieldFormSchema(Schema): + """Badge Field Form Schema""" + + badge_id = fields.String(required=True) + custom_field = fields.String(required=False) + sample_text = fields.String(required=False) + font_size = fields.Integer(required=False) + text_alignment = fields.String(required=False) + text_type = fields.String(required=False) + id = fields.Integer(required=False) + is_deleted = fields.Boolean(required=False, default=False) diff --git a/app/api/data_layers/BadgeFormLayer.py b/app/api/data_layers/BadgeFormLayer.py new file mode 100644 index 0000000000..c3367ba2bc --- /dev/null +++ b/app/api/data_layers/BadgeFormLayer.py @@ -0,0 +1,61 @@ +from flask_rest_jsonapi.data_layers.base import BaseDataLayer + +from app.api.helpers.db import save_to_db +from app.models.badge_field_form import BadgeFieldForms +from app.models.badge_form import BadgeForms + + +class BadgeFormLayer(BaseDataLayer): + """Badge Form Data Layer""" + + @staticmethod + def create_object(data, _view_kwargs): + """ + create_object method for the Badge Form Layer + charge the user using paypal or stripe + :param data: + :param _view_kwargs: + :return: + """ + badgeForm = BadgeForms() + keys = [ + 'badge_id', + 'badge_size', + 'badge_color', + 'badge_image_url', + 'badge_orientation', + ] + for key in keys: + if key in data: + badgeForm.__setattr__(key, data[key]) + + badgeForm.event_id = data['event'] + save_to_db(badgeForm) + + if 'badge_fields' in data: + keyBadgeFields = [ + 'custom_field', + 'sample_text', + 'font_size', + 'font_name', + 'font_weight', + 'font_color', + 'text_rotation', + 'text_alignment', + 'text_type', + 'is_deleted', + 'margin_top', + 'margin_bottom', + 'margin_left', + 'margin_right', + ] + for item in data['badge_fields']: + badgeFieldForm = BadgeFieldForms() + for key in keyBadgeFields: + if key in item: + badgeFieldForm.__setattr__(key, data[key]) + + badgeFieldForm.badge_id = data['badge_id'] + badgeFieldForm.badge_form_id = badgeForm.id + save_to_db(badgeFieldForm) + return badgeForm diff --git a/app/api/routes.py b/app/api/routes.py index 28a7990da7..5c910f6fea 100644 --- a/app/api/routes.py +++ b/app/api/routes.py @@ -25,6 +25,18 @@ AttendeeRelationshipOptional, AttendeeRelationshipRequired, ) +from app.api.badge_field_forms import ( + BadgeFieldFormDetail, + BadgeFieldFormList, + BadgeFieldFormListPost, + BadgeFieldFormRelationship, +) +from app.api.badge_forms import ( + BadgeFormDetail, + BadgeFormList, + BadgeFormListPost, + BadgeFormRelationship, +) from app.api.bootstrap import api from app.api.custom_form_options import ( CustomFormOptionDetail, @@ -1989,3 +2001,49 @@ 'custom_form_translate_form', '/custom-form-translates//relationships/custom-form', ) +api.route( + BadgeFormListPost, + 'badge_form_list_post', + '/badge-forms', +) +api.route( + BadgeFormList, + 'badge_form_list', + '/events//badge-forms', + '/events//badge-forms', + '/events//badge-forms/', + '/events//badge-forms/', +) +api.route( + BadgeFormDetail, + 'badge_form_detail', + '/badge-forms/', +) +api.route( + BadgeFormRelationship, + 'badge_form_event', + '/badge-forms//relationships/event', +) +api.route( + BadgeFieldFormListPost, + 'badge_field_form_list_post', + '/badge-field-forms', +) +api.route( + BadgeFieldFormList, + 'badge_field_form_list', + '/badge-forms//badge-field-forms', + '/badge-forms//badge-field-forms', + '/badge-forms//badge-field-forms/', + '/badge-forms//badge-field-forms/', +) +api.route( + BadgeFieldFormDetail, + 'badge_field_form_detail', + '/badge-field-forms/', +) +api.route( + BadgeFieldFormRelationship, + 'badge_field_form_badge_form', + '/badge-field-forms//relationships/badge_form', +) diff --git a/app/api/schema/badge_field_forms.py b/app/api/schema/badge_field_forms.py new file mode 100644 index 0000000000..42f678fdd2 --- /dev/null +++ b/app/api/schema/badge_field_forms.py @@ -0,0 +1,43 @@ +from marshmallow_jsonapi import fields +from marshmallow_jsonapi.flask import Relationship, Schema + +from app.api.helpers.utilities import dasherize +from utils.common import use_defaults + + +@use_defaults() +class BadgeFieldFormSchema(Schema): + """API Schema for Badge Field Forms database model""" + + class Meta: + """Meta class for Badge Field Form Schema""" + + type_ = 'custom-form-translate' + self_view = 'v1.badge_field_form_detail' + self_view_kwargs = {'id': ''} + inflect = dasherize + + id = fields.Integer(dump_only=True) + badge_form = Relationship( + self_view='v1.badge_field_form_badge_form', + self_view_kwargs={'id': ''}, + related_view='v1.badge_form_detail', + related_view_kwargs={'badge_field_form_id': ''}, + schema='BadgeFormSchema', + type_='badge_form', + ) + badge_id = fields.Str(required=True) + custom_field = fields.String(required=False) + sample_text = fields.String(required=False) + font_size = fields.Integer(required=False) + text_alignment = fields.String(required=False) + text_type = fields.String(required=False) + is_deleted = fields.Boolean(required=False, default=False) + font_name = fields.String(required=False) + font_weight = fields.String(required=False) + font_color = fields.String(required=False) + margin_top = fields.Integer(required=False) + margin_bottom = fields.Integer(required=False) + margin_left = fields.Integer(required=False) + margin_right = fields.Integer(required=False) + text_rotation = fields.Integer(required=False) diff --git a/app/api/schema/badge_forms.py b/app/api/schema/badge_forms.py new file mode 100644 index 0000000000..7a705d7704 --- /dev/null +++ b/app/api/schema/badge_forms.py @@ -0,0 +1,35 @@ +from marshmallow_jsonapi import fields +from marshmallow_jsonapi.flask import Relationship, Schema + +from app.api.custom.schema.badge_form_field import BadgeFieldFormSchema +from app.api.helpers.utilities import dasherize +from utils.common import use_defaults + + +@use_defaults() +class BadgeFormSchema(Schema): + """API Schema for Badge Form database model""" + + class Meta: + """Meta class for Badge Form Schema""" + + type_ = 'badge_form' + self_view = 'v1.badge_form_detail' + self_view_kwargs = {'id': ''} + inflect = dasherize + + id = fields.Integer(dump_only=True) + badge_id = fields.Str(required=True) + badge_size = fields.Str(required=False) + badge_color = fields.Str(required=False) + badge_image_url = fields.Str(required=False) + badge_orientation = fields.Str(required=False) + event = Relationship( + self_view='v1.badge_form_event', + self_view_kwargs={'id': ''}, + related_view='v1.event_detail', + related_view_kwargs={'badge_form_id': ''}, + schema='EventSchemaPublic', + type_='event', + ) + badge_fields = fields.Nested(BadgeFieldFormSchema, many=True) diff --git a/app/api/schema/tickets.py b/app/api/schema/tickets.py index 0021b12070..c41caf9c43 100644 --- a/app/api/schema/tickets.py +++ b/app/api/schema/tickets.py @@ -128,6 +128,7 @@ def validate_discount_code(self, data, original_data): is_checkin_restricted = fields.Boolean(default=True) auto_checkin_enabled = fields.Boolean(default=False) form_id = fields.Str(allow_none=True) + badge_id = fields.Str(allow_none=True) event = Relationship( self_view='v1.ticket_event', self_view_kwargs={'id': ''}, diff --git a/app/models/badge_field_form.py b/app/models/badge_field_form.py new file mode 100644 index 0000000000..24af036c19 --- /dev/null +++ b/app/models/badge_field_form.py @@ -0,0 +1,62 @@ +from app.models import db + + +class BadgeFieldForms(db.Model): + """Badge Field Form database model""" + + id = db.Column(db.Integer, primary_key=True) + badge_form_id = db.Column( + db.Integer, db.ForeignKey('badge_forms.id', ondelete='CASCADE') + ) + badge_form = db.relationship( + 'BadgeForms', backref='badge_field_form', foreign_keys=[badge_form_id] + ) + badge_id = db.Column(db.String, nullable=False) + custom_field = db.Column(db.String, nullable=False) + sample_text = db.Column(db.String, nullable=False) + font_size = db.Column(db.Integer, nullable=False) + font_name = db.Column(db.String, nullable=False) + font_weight = db.Column(db.String, nullable=False) + font_color = db.Column(db.String, nullable=False) + text_rotation = db.Column(db.Integer, nullable=False) + text_alignment = db.Column(db.String, nullable=False) + text_type = db.Column(db.String, nullable=False) + is_deleted = db.Column(db.Boolean, nullable=False) + margin_top = db.Column(db.Integer, nullable=False) + margin_bottom = db.Column(db.Integer, nullable=False) + margin_left = db.Column(db.Integer, nullable=False) + margin_right = db.Column(db.Integer, nullable=False) + + def __repr__(self): + return f'' + + def convert_to_dict(self): + """Convert object data to dictionary""" + return { + 'id': self.id, + 'custom_field': self.custom_field, + 'sample_text': self.sample_text, + 'badge_id': self.badge_id, + 'font_size': self.font_size, + 'text_alignment': self.text_alignment, + 'text_type': self.text_type, + 'is_deleted': self.is_deleted, + } + + @staticmethod + def check_badge_field_form(badge_form_id, badge_field_form_id): + """ + check custom form translate + :param badge_form_id: + :param badge_field_form_id: + :return: + """ + try: + badgeFieldForm = ( + BadgeFieldForms.query.filter_by(badge_form_id=badge_form_id) + .filter_by(id=badge_field_form_id) + .first() + ) + return badgeFieldForm + except ModuleNotFoundError: + return None diff --git a/app/models/badge_form.py b/app/models/badge_form.py new file mode 100644 index 0000000000..73d3612b6e --- /dev/null +++ b/app/models/badge_form.py @@ -0,0 +1,16 @@ +from app.models import db + + +class BadgeForms(db.Model): + """Badge Form database model""" + + id = db.Column(db.Integer, primary_key=True) + badge_id = db.Column(db.String, nullable=False) + badge_size = db.Column(db.String, nullable=False) + badge_color = db.Column(db.String, nullable=False) + badge_image_url = db.Column(db.String, nullable=False) + badge_orientation = db.Column(db.String, nullable=False) + event_id = db.Column(db.Integer, db.ForeignKey('events.id', ondelete='CASCADE')) + + def __repr__(self): + return f'' diff --git a/app/models/ticket.py b/app/models/ticket.py index d16944791b..2ebd538366 100644 --- a/app/models/ticket.py +++ b/app/models/ticket.py @@ -77,6 +77,7 @@ class Ticket(SoftDeletionModel): 'DiscountCode', secondary=discount_codes_tickets, backref="tickets" ) form_id = db.Column(db.String) + badge_id = db.Column(db.String) def has_order_tickets(self): """Returns True if ticket has already placed orders. diff --git a/migrations/versions/rev-2023-07-10-13:58:32-a03aa4fcb471_.py b/migrations/versions/rev-2023-07-10-13:58:32-a03aa4fcb471_.py new file mode 100644 index 0000000000..5f9013b964 --- /dev/null +++ b/migrations/versions/rev-2023-07-10-13:58:32-a03aa4fcb471_.py @@ -0,0 +1,62 @@ +"""empty message + +Revision ID: a03aa4fcb471 +Revises: f508644acbd3 +Create Date: 2023-07-10 13:58:32.054811 + +""" + +from alembic import op +import sqlalchemy as sa +import sqlalchemy_utils + + +# revision identifiers, used by Alembic. +revision = 'a03aa4fcb471' +down_revision = 'f508644acbd3' + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('badge_forms', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('badge_id', sa.String(), nullable=False), + sa.Column('badge_size', sa.String(), nullable=False), + sa.Column('badge_color', sa.String(), nullable=False), + sa.Column('badge_image_url', sa.String(), nullable=False), + sa.Column('badge_orientation', sa.String(), nullable=False), + sa.Column('event_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['event_id'], ['events.id'], ondelete='CASCADE'), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('badge_field_forms', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('badge_form_id', sa.Integer(), nullable=True), + sa.Column('badge_id', sa.String(), nullable=False), + sa.Column('custom_field', sa.String(), nullable=False), + sa.Column('sample_text', sa.String(), nullable=False), + sa.Column('font_size', sa.Integer(), nullable=False), + sa.Column('font_name', sa.String(), nullable=False), + sa.Column('font_weight', sa.String(), nullable=False), + sa.Column('font_color', sa.String(), nullable=False), + sa.Column('text_rotation', sa.Integer(), nullable=False), + sa.Column('text_alignment', sa.String(), nullable=False), + sa.Column('text_type', sa.String(), nullable=False), + sa.Column('is_deleted', sa.Boolean(), nullable=False), + sa.Column('margin_top', sa.Integer(), nullable=False), + sa.Column('margin_bottom', sa.Integer(), nullable=False), + sa.Column('margin_left', sa.Integer(), nullable=False), + sa.Column('margin_right', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['badge_form_id'], ['badge_forms.id'], ondelete='CASCADE'), + sa.PrimaryKeyConstraint('id') + ) + op.add_column('tickets', sa.Column('badge_id', sa.String(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('tickets', 'badge_id') + op.drop_table('badge_field_forms') + op.drop_table('badge_forms') + # ### end Alembic commands ### From 304bb1b5682b84c28f4480b09c2e576b118cb951 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Mon, 10 Jul 2023 17:58:05 +0700 Subject: [PATCH 02/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_forms.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index 4e2d748a38..1ac0880ed6 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -68,6 +68,7 @@ def after_get(badge_forms): class BadgeFormDetail(ResourceDetail): """BadgeForm Resource Detail""" + @staticmethod def before_get_object(self, view_kwargs): """ before get method @@ -201,6 +202,7 @@ class BadgeFormRelationship(ResourceRelationship): class BadgeFormListPost(ResourceList): """Create and List Custom Form Translates""" + @staticmethod def before_post(self, _args, _kwargs, data): """ method to check for required relationship with event @@ -212,7 +214,8 @@ def before_post(self, _args, _kwargs, data): require_relationship(['event'], data) if not has_access('is_coorganizer', event_id=data['event']): raise ObjectNotFound( - {'parameter': 'event_id'}, "Event: {} not found".format(data['event_id']) + {'parameter': 'event_id'}, + f"Event: {data['event_id']} not found", ) schema = BadgeFormSchema From 3adb4c8a4b9e8acfacf3356bf6502a82078778ab Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Mon, 10 Jul 2023 18:02:56 +0700 Subject: [PATCH 03/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_forms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index 1ac0880ed6..ab3ede785a 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -69,7 +69,7 @@ class BadgeFormDetail(ResourceDetail): """BadgeForm Resource Detail""" @staticmethod - def before_get_object(self, view_kwargs): + def before_get_object(view_kwargs): """ before get method :param view_kwargs: @@ -203,7 +203,7 @@ class BadgeFormListPost(ResourceList): """Create and List Custom Form Translates""" @staticmethod - def before_post(self, _args, _kwargs, data): + def before_post(_args, _kwargs, data): """ method to check for required relationship with event :param args: From 040fb44acf23ed934fd8761ea3dd9d8585908494 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Tue, 11 Jul 2023 09:12:29 +0700 Subject: [PATCH 04/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_forms.py | 18 +++++++----------- .../rev-2023-07-10-13:58:32-a03aa4fcb471_.py | 1 - 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index ab3ede785a..7ae34b162f 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -68,8 +68,7 @@ def after_get(badge_forms): class BadgeFormDetail(ResourceDetail): """BadgeForm Resource Detail""" - @staticmethod - def before_get_object(view_kwargs): + def before_get_object(self, view_kwargs): """ before get method :param view_kwargs: @@ -90,8 +89,7 @@ def before_get_object(view_kwargs): badge_form = safe_query(BadgeForms, 'event_id', event.id, 'event_id') view_kwargs['id'] = badge_form.id - @staticmethod - def before_patch(_args, kwargs, data): + def before_patch(self, _args, kwargs, data): """ before patch method :param _args: @@ -114,13 +112,13 @@ def before_patch(_args, kwargs, data): ): db.session.delete(badgeFieldForm) else: - badgeFieldForm = BadgeFieldForms() if badgeFieldForm: badgeFieldForm.badge_id = data['badge_id'] else: - badgeFieldForm.badge_id = data['form_id'] - badgeFieldForm.badge_form_id = kwargs['id'] + badgeFieldForm = BadgeFieldForms() + badgeFieldForm.badge_id = data['badge_id'] + badgeFieldForm.badge_form_id = kwargs['id'] badgeFieldForm.custom_field = badgeField['custom_field'] badgeFieldForm.sample_text = badgeField['sample_text'] badgeFieldForm.font_name = badgeField['font_name'] @@ -136,8 +134,7 @@ def before_patch(_args, kwargs, data): badgeFieldForm.margin_right = badgeField['margin_right'] db.session.add(badgeFieldForm) - @staticmethod - def before_delete(_obj, kwargs): + def before_delete(self, _obj, kwargs): """ before delete method :param _obj: @@ -148,8 +145,7 @@ def before_delete(_obj, kwargs): for item in badgeFieldForm: db.session.delete(item) - @staticmethod - def after_patch(badge_form): + def after_patch(self, badge_form): """ after patch method :param badge_form: diff --git a/migrations/versions/rev-2023-07-10-13:58:32-a03aa4fcb471_.py b/migrations/versions/rev-2023-07-10-13:58:32-a03aa4fcb471_.py index 5f9013b964..2481826a84 100644 --- a/migrations/versions/rev-2023-07-10-13:58:32-a03aa4fcb471_.py +++ b/migrations/versions/rev-2023-07-10-13:58:32-a03aa4fcb471_.py @@ -8,7 +8,6 @@ from alembic import op import sqlalchemy as sa -import sqlalchemy_utils # revision identifiers, used by Alembic. From 44e0950e1e5599b110fc3fb833d3382091883c0a Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Tue, 11 Jul 2023 09:20:11 +0700 Subject: [PATCH 05/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_forms.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index 7ae34b162f..5eebbc1274 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -89,7 +89,8 @@ def before_get_object(self, view_kwargs): badge_form = safe_query(BadgeForms, 'event_id', event.id, 'event_id') view_kwargs['id'] = badge_form.id - def before_patch(self, _args, kwargs, data): + @staticmethod + def before_patch(_args, kwargs, data): """ before patch method :param _args: @@ -134,7 +135,8 @@ def before_patch(self, _args, kwargs, data): badgeFieldForm.margin_right = badgeField['margin_right'] db.session.add(badgeFieldForm) - def before_delete(self, _obj, kwargs): + @staticmethod + def before_delete(_obj, kwargs): """ before delete method :param _obj: @@ -145,7 +147,8 @@ def before_delete(self, _obj, kwargs): for item in badgeFieldForm: db.session.delete(item) - def after_patch(self, badge_form): + @staticmethod + def after_patch(badge_form): """ after patch method :param badge_form: From 3d73add166a34b02bf326676dc05239224629ea6 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Tue, 11 Jul 2023 09:47:22 +0700 Subject: [PATCH 06/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_forms.py | 1 + app/api/data_layers/BadgeFormLayer.py | 1 + app/api/schema/badge_field_forms.py | 1 + app/models/badge_field_form.py | 1 + ...cb471_.py => rev-2023-07-11-09:46:28-284704f87457_.py} | 8 +++++--- 5 files changed, 9 insertions(+), 3 deletions(-) rename migrations/versions/{rev-2023-07-10-13:58:32-a03aa4fcb471_.py => rev-2023-07-11-09:46:28-284704f87457_.py} (92%) diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index 5eebbc1274..9937d7009e 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -133,6 +133,7 @@ def before_patch(_args, kwargs, data): badgeFieldForm.margin_bottom = badgeField['margin_bottom'] badgeFieldForm.margin_left = badgeField['margin_left'] badgeFieldForm.margin_right = badgeField['margin_right'] + badgeFieldForm.qr_custom_field = badgeField['qr_custom_field'] db.session.add(badgeFieldForm) @staticmethod diff --git a/app/api/data_layers/BadgeFormLayer.py b/app/api/data_layers/BadgeFormLayer.py index c3367ba2bc..155e3b2277 100644 --- a/app/api/data_layers/BadgeFormLayer.py +++ b/app/api/data_layers/BadgeFormLayer.py @@ -48,6 +48,7 @@ def create_object(data, _view_kwargs): 'margin_bottom', 'margin_left', 'margin_right', + 'qr_custom_field', ] for item in data['badge_fields']: badgeFieldForm = BadgeFieldForms() diff --git a/app/api/schema/badge_field_forms.py b/app/api/schema/badge_field_forms.py index 42f678fdd2..396d369b8c 100644 --- a/app/api/schema/badge_field_forms.py +++ b/app/api/schema/badge_field_forms.py @@ -41,3 +41,4 @@ class Meta: margin_left = fields.Integer(required=False) margin_right = fields.Integer(required=False) text_rotation = fields.Integer(required=False) + qr_custom_field = fields.String(required=False) diff --git a/app/models/badge_field_form.py b/app/models/badge_field_form.py index 24af036c19..02abc38500 100644 --- a/app/models/badge_field_form.py +++ b/app/models/badge_field_form.py @@ -26,6 +26,7 @@ class BadgeFieldForms(db.Model): margin_bottom = db.Column(db.Integer, nullable=False) margin_left = db.Column(db.Integer, nullable=False) margin_right = db.Column(db.Integer, nullable=False) + qr_custom_field = db.Column(db.String, nullable=False) def __repr__(self): return f'' diff --git a/migrations/versions/rev-2023-07-10-13:58:32-a03aa4fcb471_.py b/migrations/versions/rev-2023-07-11-09:46:28-284704f87457_.py similarity index 92% rename from migrations/versions/rev-2023-07-10-13:58:32-a03aa4fcb471_.py rename to migrations/versions/rev-2023-07-11-09:46:28-284704f87457_.py index 2481826a84..0a9b2f4de9 100644 --- a/migrations/versions/rev-2023-07-10-13:58:32-a03aa4fcb471_.py +++ b/migrations/versions/rev-2023-07-11-09:46:28-284704f87457_.py @@ -1,17 +1,18 @@ """empty message -Revision ID: a03aa4fcb471 +Revision ID: 284704f87457 Revises: f508644acbd3 -Create Date: 2023-07-10 13:58:32.054811 +Create Date: 2023-07-11 09:46:28.462980 """ from alembic import op import sqlalchemy as sa +import sqlalchemy_utils # revision identifiers, used by Alembic. -revision = 'a03aa4fcb471' +revision = '284704f87457' down_revision = 'f508644acbd3' @@ -46,6 +47,7 @@ def upgrade(): sa.Column('margin_bottom', sa.Integer(), nullable=False), sa.Column('margin_left', sa.Integer(), nullable=False), sa.Column('margin_right', sa.Integer(), nullable=False), + sa.Column('qr_custom_field', sa.String(), nullable=False), sa.ForeignKeyConstraint(['badge_form_id'], ['badge_forms.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id') ) From c2ac4fc13e1728b2d7628ab235f9fb7463acd567 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Tue, 11 Jul 2023 09:57:54 +0700 Subject: [PATCH 07/37] feature-8683: Add Options for Badges in Wizard --- migrations/versions/rev-2023-07-11-09:46:28-284704f87457_.py | 1 - 1 file changed, 1 deletion(-) diff --git a/migrations/versions/rev-2023-07-11-09:46:28-284704f87457_.py b/migrations/versions/rev-2023-07-11-09:46:28-284704f87457_.py index 0a9b2f4de9..6764dc294b 100644 --- a/migrations/versions/rev-2023-07-11-09:46:28-284704f87457_.py +++ b/migrations/versions/rev-2023-07-11-09:46:28-284704f87457_.py @@ -8,7 +8,6 @@ from alembic import op import sqlalchemy as sa -import sqlalchemy_utils # revision identifiers, used by Alembic. From 33a7fa12019952a67ded3f3d7ce3d1a98fa39697 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Tue, 11 Jul 2023 11:37:58 +0700 Subject: [PATCH 08/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_forms.py | 23 ++++++++++++----------- app/api/custom/schema/badge_form_field.py | 9 +++++++++ app/api/data_layers/BadgeFormLayer.py | 4 ++-- app/api/routes.py | 7 +++++++ app/api/schema/badge_forms.py | 2 +- app/api/schema/events.py | 10 ++++++++++ app/models/badge_field_form.py | 9 +++++++++ app/models/badge_form.py | 1 + 8 files changed, 51 insertions(+), 14 deletions(-) diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index 9937d7009e..fee56ceb43 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -61,7 +61,7 @@ def after_get(badge_forms): data_layer = { 'session': db.session, 'model': BadgeForms, - 'methods': {'query': query}, + 'methods': {'query': query, 'after_get': after_get}, } @@ -108,7 +108,7 @@ def before_patch(_args, kwargs, data): ) if ( badgeFieldForm is not None - and 'isDeleted' in badgeField + and 'is_deleted' in badgeField and badgeField['is_deleted'] ): db.session.delete(badgeFieldForm) @@ -134,6 +134,7 @@ def before_patch(_args, kwargs, data): badgeFieldForm.margin_left = badgeField['margin_left'] badgeFieldForm.margin_right = badgeField['margin_right'] badgeFieldForm.qr_custom_field = badgeField['qr_custom_field'] + badgeFieldForm.is_deleted = False db.session.add(badgeFieldForm) @staticmethod @@ -158,15 +159,15 @@ def after_patch(badge_form): badgeFields = [] data = badge_form['data'] attributes = data['attributes'] - if attributes and attributes['is-complex']: - badgeFieldForms = ( - BadgeFieldForms.query.filter_by(badge_form_id=data['id']) - .filter_by(form_id=attributes['form-id']) - .all() - ) - for badgeFieldForm in badgeFieldForms: - badgeFields.append(badgeFieldForm.convert_to_dict()) - attributes['badge_fields'] = badgeFields + print(badge_form) + badgeFieldForms = ( + BadgeFieldForms.query.filter_by(badge_form_id=data['id']) + .filter_by(badge_id=attributes['badge-id']) + .all() + ) + for badgeFieldForm in badgeFieldForms: + badgeFields.append(badgeFieldForm.convert_to_dict()) + attributes['badge_fields'] = badgeFields return badge_form decorators = ( diff --git a/app/api/custom/schema/badge_form_field.py b/app/api/custom/schema/badge_form_field.py index 597a273fc6..84bef9f7eb 100644 --- a/app/api/custom/schema/badge_form_field.py +++ b/app/api/custom/schema/badge_form_field.py @@ -8,7 +8,16 @@ class BadgeFieldFormSchema(Schema): custom_field = fields.String(required=False) sample_text = fields.String(required=False) font_size = fields.Integer(required=False) + font_name = fields.String(required=False) + font_weight = fields.String(required=False) + font_color = fields.String(required=False) + text_rotation = fields.Integer(required=False) text_alignment = fields.String(required=False) text_type = fields.String(required=False) id = fields.Integer(required=False) is_deleted = fields.Boolean(required=False, default=False) + margin_top = fields.Integer(required=False) + margin_bottom = fields.Integer(required=False) + margin_left = fields.Integer(required=False) + margin_right = fields.Integer(required=False) + qr_custom_field = fields.String(required=False) diff --git a/app/api/data_layers/BadgeFormLayer.py b/app/api/data_layers/BadgeFormLayer.py index 155e3b2277..817e0d8211 100644 --- a/app/api/data_layers/BadgeFormLayer.py +++ b/app/api/data_layers/BadgeFormLayer.py @@ -54,9 +54,9 @@ def create_object(data, _view_kwargs): badgeFieldForm = BadgeFieldForms() for key in keyBadgeFields: if key in item: - badgeFieldForm.__setattr__(key, data[key]) + badgeFieldForm.__setattr__(key, item[key]) - badgeFieldForm.badge_id = data['badge_id'] + badgeFieldForm.badge_id = item['badge_id'] badgeFieldForm.badge_form_id = badgeForm.id save_to_db(badgeFieldForm) return badgeForm diff --git a/app/api/routes.py b/app/api/routes.py index 5c910f6fea..310ba93e35 100644 --- a/app/api/routes.py +++ b/app/api/routes.py @@ -815,6 +815,7 @@ '/users-events-roles//event', '/exhibitors//event', '/speaker-invites//event', + '/badge-forms//event', ) api.route( EventRelationship, @@ -942,6 +943,12 @@ '/events//relationships/custom-forms', '/events//relationships/custom-forms', ) +api.route( + EventRelationship, + 'event_badge_forms', + '/events//relationships/badge-forms', + '/events//relationships/badge-forms', +) api.route( EventRelationship, 'event_faqs', diff --git a/app/api/schema/badge_forms.py b/app/api/schema/badge_forms.py index 7a705d7704..82c5a1649f 100644 --- a/app/api/schema/badge_forms.py +++ b/app/api/schema/badge_forms.py @@ -13,7 +13,7 @@ class BadgeFormSchema(Schema): class Meta: """Meta class for Badge Form Schema""" - type_ = 'badge_form' + type_ = 'badge-form' self_view = 'v1.badge_form_detail' self_view_kwargs = {'id': ''} inflect = dasherize diff --git a/app/api/schema/events.py b/app/api/schema/events.py index 2b9ce5539e..1e1a769f84 100644 --- a/app/api/schema/events.py +++ b/app/api/schema/events.py @@ -384,6 +384,16 @@ def validate_timezone(self, data, original_data): type_='speaker-invite', many=True, ) + badge_forms = Relationship( + attribute='badge_form', + self_view='v1.event_badge_forms', + self_view_kwargs={'id': ''}, + related_view='v1.badge_form_list', + related_view_kwargs={'event_id': ''}, + schema='BadgeFormSchema', + many=True, + type_='badge-form', + ) class EventSchema(EventSchemaPublic): diff --git a/app/models/badge_field_form.py b/app/models/badge_field_form.py index 02abc38500..d3e52f48c4 100644 --- a/app/models/badge_field_form.py +++ b/app/models/badge_field_form.py @@ -39,9 +39,18 @@ def convert_to_dict(self): 'sample_text': self.sample_text, 'badge_id': self.badge_id, 'font_size': self.font_size, + 'font_name': self.font_name, + 'font_weight': self.font_weight, + 'font_color': self.font_color, + 'text_rotation': self.text_rotation, 'text_alignment': self.text_alignment, 'text_type': self.text_type, 'is_deleted': self.is_deleted, + 'margin_top': self.margin_top, + 'margin_bottom': self.margin_bottom, + 'margin_left': self.margin_left, + 'margin_right': self.margin_right, + 'qr_custom_field': self.qr_custom_field, } @staticmethod diff --git a/app/models/badge_form.py b/app/models/badge_form.py index 73d3612b6e..deac728ec1 100644 --- a/app/models/badge_form.py +++ b/app/models/badge_form.py @@ -11,6 +11,7 @@ class BadgeForms(db.Model): badge_image_url = db.Column(db.String, nullable=False) badge_orientation = db.Column(db.String, nullable=False) event_id = db.Column(db.Integer, db.ForeignKey('events.id', ondelete='CASCADE')) + event = db.relationship('Event', backref='badge_forms_') def __repr__(self): return f'' From f4db85ad1a6cad35d92c97928a6734aa0504b4c6 Mon Sep 17 00:00:00 2001 From: khangon Date: Wed, 12 Jul 2023 13:26:34 +0700 Subject: [PATCH 09/37] feature-8683: Add Options for Badges in Wizard imeplemnent save badge --- app/api/badge_forms.py | 2 +- app/api/custom/schema/badge_form_field.py | 34 +++++++------- app/api/schema/badge_forms.py | 10 ++--- app/models/badge_field_form.py | 30 ++++++------- app/models/badge_form.py | 8 ++-- ... rev-2023-07-12-10:41:23-a4dd30cc8af1_.py} | 45 ++++++++++--------- 6 files changed, 65 insertions(+), 64 deletions(-) rename migrations/versions/{rev-2023-07-11-09:46:28-284704f87457_.py => rev-2023-07-12-10:41:23-a4dd30cc8af1_.py} (50%) diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index fee56ceb43..92bd0ff31e 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -48,7 +48,7 @@ def after_get(badge_forms): .all() ) for badgeFieldForm in badgeFieldForms: - badgeFieldForms.append(badgeFieldForm.convert_to_dict()) + badgeFields.append(badgeFieldForm.convert_to_dict()) item['attributes']['badge_fields'] = badgeFields return badge_forms diff --git a/app/api/custom/schema/badge_form_field.py b/app/api/custom/schema/badge_form_field.py index 84bef9f7eb..6c07ce683a 100644 --- a/app/api/custom/schema/badge_form_field.py +++ b/app/api/custom/schema/badge_form_field.py @@ -4,20 +4,20 @@ class BadgeFieldFormSchema(Schema): """Badge Field Form Schema""" - badge_id = fields.String(required=True) - custom_field = fields.String(required=False) - sample_text = fields.String(required=False) - font_size = fields.Integer(required=False) - font_name = fields.String(required=False) - font_weight = fields.String(required=False) - font_color = fields.String(required=False) - text_rotation = fields.Integer(required=False) - text_alignment = fields.String(required=False) - text_type = fields.String(required=False) - id = fields.Integer(required=False) - is_deleted = fields.Boolean(required=False, default=False) - margin_top = fields.Integer(required=False) - margin_bottom = fields.Integer(required=False) - margin_left = fields.Integer(required=False) - margin_right = fields.Integer(required=False) - qr_custom_field = fields.String(required=False) + badge_id = fields.String(allow_none=False) + custom_field = fields.String(allow_none=True) + sample_text = fields.String(allow_none=True) + font_size = fields.Integer(allow_none=True) + font_name = fields.String(allow_none=True) + font_weight = fields.String(allow_none=True) + font_color = fields.String(allow_none=True) + text_rotation = fields.Integer(allow_none=True) + text_alignment = fields.String(allow_none=True) + text_type = fields.String(allow_none=True) + id = fields.Integer(allow_none=True) + is_deleted = fields.Boolean(allow_none=True, default=False) + margin_top = fields.Integer(allow_none=True) + margin_bottom = fields.Integer(allow_none=True) + margin_left = fields.Integer(allow_none=True) + margin_right = fields.Integer(allow_none=True) + qr_custom_field = fields.String(allow_none=True) diff --git a/app/api/schema/badge_forms.py b/app/api/schema/badge_forms.py index 82c5a1649f..a9a3bdfdb0 100644 --- a/app/api/schema/badge_forms.py +++ b/app/api/schema/badge_forms.py @@ -19,11 +19,11 @@ class Meta: inflect = dasherize id = fields.Integer(dump_only=True) - badge_id = fields.Str(required=True) - badge_size = fields.Str(required=False) - badge_color = fields.Str(required=False) - badge_image_url = fields.Str(required=False) - badge_orientation = fields.Str(required=False) + badge_id = fields.String(allow_none=False) + badge_size = fields.String(allow_none=True) + badge_color = fields.String(allow_none=True) + badge_image_url = fields.String(allow_none=True) + badge_orientation = fields.String(allow_none=True) event = Relationship( self_view='v1.badge_form_event', self_view_kwargs={'id': ''}, diff --git a/app/models/badge_field_form.py b/app/models/badge_field_form.py index d3e52f48c4..08082f7c87 100644 --- a/app/models/badge_field_form.py +++ b/app/models/badge_field_form.py @@ -12,21 +12,21 @@ class BadgeFieldForms(db.Model): 'BadgeForms', backref='badge_field_form', foreign_keys=[badge_form_id] ) badge_id = db.Column(db.String, nullable=False) - custom_field = db.Column(db.String, nullable=False) - sample_text = db.Column(db.String, nullable=False) - font_size = db.Column(db.Integer, nullable=False) - font_name = db.Column(db.String, nullable=False) - font_weight = db.Column(db.String, nullable=False) - font_color = db.Column(db.String, nullable=False) - text_rotation = db.Column(db.Integer, nullable=False) - text_alignment = db.Column(db.String, nullable=False) - text_type = db.Column(db.String, nullable=False) - is_deleted = db.Column(db.Boolean, nullable=False) - margin_top = db.Column(db.Integer, nullable=False) - margin_bottom = db.Column(db.Integer, nullable=False) - margin_left = db.Column(db.Integer, nullable=False) - margin_right = db.Column(db.Integer, nullable=False) - qr_custom_field = db.Column(db.String, nullable=False) + custom_field = db.Column(db.String, nullable=True) + sample_text = db.Column(db.String, nullable=True) + font_size = db.Column(db.Integer, nullable=True) + font_name = db.Column(db.String, nullable=True) + font_weight = db.Column(db.String, nullable=True) + font_color = db.Column(db.String, nullable=True) + text_rotation = db.Column(db.Integer, nullable=True) + text_alignment = db.Column(db.String, nullable=True) + text_type = db.Column(db.String, nullable=True) + is_deleted = db.Column(db.Boolean, nullable=True) + margin_top = db.Column(db.Integer, nullable=True) + margin_bottom = db.Column(db.Integer, nullable=True) + margin_left = db.Column(db.Integer, nullable=True) + margin_right = db.Column(db.Integer, nullable=True) + qr_custom_field = db.Column(db.String, nullable=True) def __repr__(self): return f'' diff --git a/app/models/badge_form.py b/app/models/badge_form.py index deac728ec1..166f236483 100644 --- a/app/models/badge_form.py +++ b/app/models/badge_form.py @@ -6,10 +6,10 @@ class BadgeForms(db.Model): id = db.Column(db.Integer, primary_key=True) badge_id = db.Column(db.String, nullable=False) - badge_size = db.Column(db.String, nullable=False) - badge_color = db.Column(db.String, nullable=False) - badge_image_url = db.Column(db.String, nullable=False) - badge_orientation = db.Column(db.String, nullable=False) + badge_size = db.Column(db.String, nullable=True) + badge_color = db.Column(db.String, nullable=True) + badge_image_url = db.Column(db.String, nullable=True) + badge_orientation = db.Column(db.String, nullable=True) event_id = db.Column(db.Integer, db.ForeignKey('events.id', ondelete='CASCADE')) event = db.relationship('Event', backref='badge_forms_') diff --git a/migrations/versions/rev-2023-07-11-09:46:28-284704f87457_.py b/migrations/versions/rev-2023-07-12-10:41:23-a4dd30cc8af1_.py similarity index 50% rename from migrations/versions/rev-2023-07-11-09:46:28-284704f87457_.py rename to migrations/versions/rev-2023-07-12-10:41:23-a4dd30cc8af1_.py index 6764dc294b..79898102ec 100644 --- a/migrations/versions/rev-2023-07-11-09:46:28-284704f87457_.py +++ b/migrations/versions/rev-2023-07-12-10:41:23-a4dd30cc8af1_.py @@ -1,17 +1,18 @@ """empty message -Revision ID: 284704f87457 +Revision ID: a4dd30cc8af1 Revises: f508644acbd3 -Create Date: 2023-07-11 09:46:28.462980 +Create Date: 2023-07-12 10:41:23.082067 """ from alembic import op import sqlalchemy as sa +import sqlalchemy_utils # revision identifiers, used by Alembic. -revision = '284704f87457' +revision = 'a4dd30cc8af1' down_revision = 'f508644acbd3' @@ -20,10 +21,10 @@ def upgrade(): op.create_table('badge_forms', sa.Column('id', sa.Integer(), nullable=False), sa.Column('badge_id', sa.String(), nullable=False), - sa.Column('badge_size', sa.String(), nullable=False), - sa.Column('badge_color', sa.String(), nullable=False), - sa.Column('badge_image_url', sa.String(), nullable=False), - sa.Column('badge_orientation', sa.String(), nullable=False), + sa.Column('badge_size', sa.String(), nullable=True), + sa.Column('badge_color', sa.String(), nullable=True), + sa.Column('badge_image_url', sa.String(), nullable=True), + sa.Column('badge_orientation', sa.String(), nullable=True), sa.Column('event_id', sa.Integer(), nullable=True), sa.ForeignKeyConstraint(['event_id'], ['events.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id') @@ -32,21 +33,21 @@ def upgrade(): sa.Column('id', sa.Integer(), nullable=False), sa.Column('badge_form_id', sa.Integer(), nullable=True), sa.Column('badge_id', sa.String(), nullable=False), - sa.Column('custom_field', sa.String(), nullable=False), - sa.Column('sample_text', sa.String(), nullable=False), - sa.Column('font_size', sa.Integer(), nullable=False), - sa.Column('font_name', sa.String(), nullable=False), - sa.Column('font_weight', sa.String(), nullable=False), - sa.Column('font_color', sa.String(), nullable=False), - sa.Column('text_rotation', sa.Integer(), nullable=False), - sa.Column('text_alignment', sa.String(), nullable=False), - sa.Column('text_type', sa.String(), nullable=False), - sa.Column('is_deleted', sa.Boolean(), nullable=False), - sa.Column('margin_top', sa.Integer(), nullable=False), - sa.Column('margin_bottom', sa.Integer(), nullable=False), - sa.Column('margin_left', sa.Integer(), nullable=False), - sa.Column('margin_right', sa.Integer(), nullable=False), - sa.Column('qr_custom_field', sa.String(), nullable=False), + sa.Column('custom_field', sa.String(), nullable=True), + sa.Column('sample_text', sa.String(), nullable=True), + sa.Column('font_size', sa.Integer(), nullable=True), + sa.Column('font_name', sa.String(), nullable=True), + sa.Column('font_weight', sa.String(), nullable=True), + sa.Column('font_color', sa.String(), nullable=True), + sa.Column('text_rotation', sa.Integer(), nullable=True), + sa.Column('text_alignment', sa.String(), nullable=True), + sa.Column('text_type', sa.String(), nullable=True), + sa.Column('is_deleted', sa.Boolean(), nullable=True), + sa.Column('margin_top', sa.Integer(), nullable=True), + sa.Column('margin_bottom', sa.Integer(), nullable=True), + sa.Column('margin_left', sa.Integer(), nullable=True), + sa.Column('margin_right', sa.Integer(), nullable=True), + sa.Column('qr_custom_field', sa.String(), nullable=True), sa.ForeignKeyConstraint(['badge_form_id'], ['badge_forms.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id') ) From 41ec4fa42ec14640766bd7d4206be1af77057263 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Thu, 13 Jul 2023 10:30:53 +0700 Subject: [PATCH 10/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_forms.py | 8 ++++---- app/api/custom/schema/badge_form_field.py | 4 ++-- app/api/data_layers/BadgeFormLayer.py | 2 +- app/api/schema/badge_field_forms.py | 4 ++-- app/models/badge_field_form.py | 4 ++-- ...c8af1_.py => rev-2023-07-12-15:31:49-d1c4a3c3f83b_.py} | 8 ++++---- 6 files changed, 15 insertions(+), 15 deletions(-) rename migrations/versions/{rev-2023-07-12-10:41:23-a4dd30cc8af1_.py => rev-2023-07-12-15:31:49-d1c4a3c3f83b_.py} (93%) diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index 92bd0ff31e..812dabbfee 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -49,7 +49,7 @@ def after_get(badge_forms): ) for badgeFieldForm in badgeFieldForms: badgeFields.append(badgeFieldForm.convert_to_dict()) - item['attributes']['badge_fields'] = badgeFields + item['attributes']['badge-fields'] = badgeFields return badge_forms view_kwargs = True @@ -108,8 +108,8 @@ def before_patch(_args, kwargs, data): ) if ( badgeFieldForm is not None - and 'is_deleted' in badgeField - and badgeField['is_deleted'] + and 'isDeleted' in badgeField + and badgeField['isDeleted'] ): db.session.delete(badgeFieldForm) else: @@ -167,7 +167,7 @@ def after_patch(badge_form): ) for badgeFieldForm in badgeFieldForms: badgeFields.append(badgeFieldForm.convert_to_dict()) - attributes['badge_fields'] = badgeFields + attributes['badge-fields'] = badgeFields return badge_form decorators = ( diff --git a/app/api/custom/schema/badge_form_field.py b/app/api/custom/schema/badge_form_field.py index 6c07ce683a..d009089b84 100644 --- a/app/api/custom/schema/badge_form_field.py +++ b/app/api/custom/schema/badge_form_field.py @@ -9,13 +9,13 @@ class BadgeFieldFormSchema(Schema): sample_text = fields.String(allow_none=True) font_size = fields.Integer(allow_none=True) font_name = fields.String(allow_none=True) - font_weight = fields.String(allow_none=True) + font_weight = fields.Integer(allow_none=True) font_color = fields.String(allow_none=True) text_rotation = fields.Integer(allow_none=True) text_alignment = fields.String(allow_none=True) text_type = fields.String(allow_none=True) id = fields.Integer(allow_none=True) - is_deleted = fields.Boolean(allow_none=True, default=False) + isDeleted = fields.Boolean(allow_none=True, default=False) margin_top = fields.Integer(allow_none=True) margin_bottom = fields.Integer(allow_none=True) margin_left = fields.Integer(allow_none=True) diff --git a/app/api/data_layers/BadgeFormLayer.py b/app/api/data_layers/BadgeFormLayer.py index 817e0d8211..0e6c723157 100644 --- a/app/api/data_layers/BadgeFormLayer.py +++ b/app/api/data_layers/BadgeFormLayer.py @@ -43,7 +43,6 @@ def create_object(data, _view_kwargs): 'text_rotation', 'text_alignment', 'text_type', - 'is_deleted', 'margin_top', 'margin_bottom', 'margin_left', @@ -57,6 +56,7 @@ def create_object(data, _view_kwargs): badgeFieldForm.__setattr__(key, item[key]) badgeFieldForm.badge_id = item['badge_id'] + badgeFieldForm.is_deleted = item['isDeleted'] badgeFieldForm.badge_form_id = badgeForm.id save_to_db(badgeFieldForm) return badgeForm diff --git a/app/api/schema/badge_field_forms.py b/app/api/schema/badge_field_forms.py index 396d369b8c..e8145fd77d 100644 --- a/app/api/schema/badge_field_forms.py +++ b/app/api/schema/badge_field_forms.py @@ -32,9 +32,9 @@ class Meta: font_size = fields.Integer(required=False) text_alignment = fields.String(required=False) text_type = fields.String(required=False) - is_deleted = fields.Boolean(required=False, default=False) + isDeleted = fields.Boolean(required=False, default=False) font_name = fields.String(required=False) - font_weight = fields.String(required=False) + font_weight = fields.Integer(required=False) font_color = fields.String(required=False) margin_top = fields.Integer(required=False) margin_bottom = fields.Integer(required=False) diff --git a/app/models/badge_field_form.py b/app/models/badge_field_form.py index 08082f7c87..6c8a44a3c5 100644 --- a/app/models/badge_field_form.py +++ b/app/models/badge_field_form.py @@ -16,7 +16,7 @@ class BadgeFieldForms(db.Model): sample_text = db.Column(db.String, nullable=True) font_size = db.Column(db.Integer, nullable=True) font_name = db.Column(db.String, nullable=True) - font_weight = db.Column(db.String, nullable=True) + font_weight = db.Column(db.Integer, nullable=True) font_color = db.Column(db.String, nullable=True) text_rotation = db.Column(db.Integer, nullable=True) text_alignment = db.Column(db.String, nullable=True) @@ -45,7 +45,7 @@ def convert_to_dict(self): 'text_rotation': self.text_rotation, 'text_alignment': self.text_alignment, 'text_type': self.text_type, - 'is_deleted': self.is_deleted, + 'isDeleted': self.is_deleted, 'margin_top': self.margin_top, 'margin_bottom': self.margin_bottom, 'margin_left': self.margin_left, diff --git a/migrations/versions/rev-2023-07-12-10:41:23-a4dd30cc8af1_.py b/migrations/versions/rev-2023-07-12-15:31:49-d1c4a3c3f83b_.py similarity index 93% rename from migrations/versions/rev-2023-07-12-10:41:23-a4dd30cc8af1_.py rename to migrations/versions/rev-2023-07-12-15:31:49-d1c4a3c3f83b_.py index 79898102ec..84dae6a168 100644 --- a/migrations/versions/rev-2023-07-12-10:41:23-a4dd30cc8af1_.py +++ b/migrations/versions/rev-2023-07-12-15:31:49-d1c4a3c3f83b_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: a4dd30cc8af1 +Revision ID: d1c4a3c3f83b Revises: f508644acbd3 -Create Date: 2023-07-12 10:41:23.082067 +Create Date: 2023-07-12 15:31:49.477098 """ @@ -12,7 +12,7 @@ # revision identifiers, used by Alembic. -revision = 'a4dd30cc8af1' +revision = 'd1c4a3c3f83b' down_revision = 'f508644acbd3' @@ -37,7 +37,7 @@ def upgrade(): sa.Column('sample_text', sa.String(), nullable=True), sa.Column('font_size', sa.Integer(), nullable=True), sa.Column('font_name', sa.String(), nullable=True), - sa.Column('font_weight', sa.String(), nullable=True), + sa.Column('font_weight', sa.Integer(), nullable=True), sa.Column('font_color', sa.String(), nullable=True), sa.Column('text_rotation', sa.Integer(), nullable=True), sa.Column('text_alignment', sa.String(), nullable=True), From 92bd59fd8070edb979c746b5b766c1c373f3a57a Mon Sep 17 00:00:00 2001 From: khangon Date: Thu, 13 Jul 2023 15:48:13 +0700 Subject: [PATCH 11/37] feature-8683: Add Options for Badges in Wizard --- app/api/custom/schema/badge_form_field.py | 2 +- app/api/schema/badge_field_forms.py | 2 +- app/models/badge_field_form.py | 6 ++++-- ...b_.py => rev-2023-07-13-15:05:52-3f0debd44275_.py} | 11 +++++------ 4 files changed, 11 insertions(+), 10 deletions(-) rename migrations/versions/{rev-2023-07-12-15:31:49-d1c4a3c3f83b_.py => rev-2023-07-13-15:05:52-3f0debd44275_.py} (91%) diff --git a/app/api/custom/schema/badge_form_field.py b/app/api/custom/schema/badge_form_field.py index d009089b84..f411ac8254 100644 --- a/app/api/custom/schema/badge_form_field.py +++ b/app/api/custom/schema/badge_form_field.py @@ -20,4 +20,4 @@ class BadgeFieldFormSchema(Schema): margin_bottom = fields.Integer(allow_none=True) margin_left = fields.Integer(allow_none=True) margin_right = fields.Integer(allow_none=True) - qr_custom_field = fields.String(allow_none=True) + qr_custom_field = fields.List(fields.String(), allow_none=True) diff --git a/app/api/schema/badge_field_forms.py b/app/api/schema/badge_field_forms.py index e8145fd77d..0f809c4c23 100644 --- a/app/api/schema/badge_field_forms.py +++ b/app/api/schema/badge_field_forms.py @@ -41,4 +41,4 @@ class Meta: margin_left = fields.Integer(required=False) margin_right = fields.Integer(required=False) text_rotation = fields.Integer(required=False) - qr_custom_field = fields.String(required=False) + qr_custom_field = fields.List(fields.String(), required=False) diff --git a/app/models/badge_field_form.py b/app/models/badge_field_form.py index 6c8a44a3c5..7ae3f283d0 100644 --- a/app/models/badge_field_form.py +++ b/app/models/badge_field_form.py @@ -1,5 +1,6 @@ +from sqlalchemy import String from app.models import db - +from sqlalchemy.dialects.postgresql import ARRAY class BadgeFieldForms(db.Model): """Badge Field Form database model""" @@ -26,7 +27,8 @@ class BadgeFieldForms(db.Model): margin_bottom = db.Column(db.Integer, nullable=True) margin_left = db.Column(db.Integer, nullable=True) margin_right = db.Column(db.Integer, nullable=True) - qr_custom_field = db.Column(db.String, nullable=True) + qr_custom_field = db.Column(ARRAY(String),nullable=True) + def __repr__(self): return f'' diff --git a/migrations/versions/rev-2023-07-12-15:31:49-d1c4a3c3f83b_.py b/migrations/versions/rev-2023-07-13-15:05:52-3f0debd44275_.py similarity index 91% rename from migrations/versions/rev-2023-07-12-15:31:49-d1c4a3c3f83b_.py rename to migrations/versions/rev-2023-07-13-15:05:52-3f0debd44275_.py index 84dae6a168..835345d149 100644 --- a/migrations/versions/rev-2023-07-12-15:31:49-d1c4a3c3f83b_.py +++ b/migrations/versions/rev-2023-07-13-15:05:52-3f0debd44275_.py @@ -1,18 +1,17 @@ """empty message -Revision ID: d1c4a3c3f83b +Revision ID: 3f0debd44275 Revises: f508644acbd3 -Create Date: 2023-07-12 15:31:49.477098 +Create Date: 2023-07-13 15:05:52.627311 """ from alembic import op import sqlalchemy as sa -import sqlalchemy_utils - +from sqlalchemy.dialects import postgresql # revision identifiers, used by Alembic. -revision = 'd1c4a3c3f83b' +revision = '3f0debd44275' down_revision = 'f508644acbd3' @@ -47,7 +46,7 @@ def upgrade(): sa.Column('margin_bottom', sa.Integer(), nullable=True), sa.Column('margin_left', sa.Integer(), nullable=True), sa.Column('margin_right', sa.Integer(), nullable=True), - sa.Column('qr_custom_field', sa.String(), nullable=True), + sa.Column('qr_custom_field', postgresql.ARRAY(sa.String()), nullable=True), sa.ForeignKeyConstraint(['badge_form_id'], ['badge_forms.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id') ) From 16b93f380b74e969e8348fd3b6bb4ff6e764cec8 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Thu, 13 Jul 2023 18:13:36 +0700 Subject: [PATCH 12/37] feature-8683: Add Options for Badges in Wizard --- app/api/custom/badge_forms.py | 59 ++++++++++++++++++++++++++++++ app/api/helpers/badge_forms.py | 55 ++++++++++++++++++++++++++++ app/api/helpers/storage.py | 1 + app/instance.py | 2 + app/templates/pdf/badge_forms.html | 30 +++++++++++++++ 5 files changed, 147 insertions(+) create mode 100644 app/api/custom/badge_forms.py create mode 100644 app/api/helpers/badge_forms.py create mode 100644 app/templates/pdf/badge_forms.html diff --git a/app/api/custom/badge_forms.py b/app/api/custom/badge_forms.py new file mode 100644 index 0000000000..99b93ca438 --- /dev/null +++ b/app/api/custom/badge_forms.py @@ -0,0 +1,59 @@ +from flask import Blueprint, request +from flask.helpers import send_from_directory +from flask_jwt_extended import jwt_required + +from app.api.helpers.badge_forms import create_preivew_badge_pdf, create_print_badge_pdf +from app.api.helpers.errors import ForbiddenError, NotFoundError +from app.api.helpers.permission_manager import has_access +from app.api.helpers.storage import UPLOAD_PATHS, generate_hash +from app.models.badge_form import BadgeForms +from app.models.ticket_holder import TicketHolder + +badge_forms_routes = Blueprint( + 'badge_forms_routes', __name__, url_prefix='/v1/badge-forms' +) + + +def file_pdf_path(self) -> str: + key = UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=self.badge_id) + return f'static/media/{key}/{generate_hash(key)}/{self.badge_id}.pdf' + + +@badge_forms_routes.route('/preivew-badge-pdf/') +@jwt_required +def preivew_badge_pdf(badge_id): + badgeForms = BadgeForms.query.filter_by(badge_id=badge_id).first() + if badgeForms is None: + raise NotFoundError( + {'source': ''}, 'This badge form is not associated with any ticket' + ) + + if not (has_access('is_coorganizer', event_id=badgeForms.event_id)): + raise ForbiddenError({'source': ''}, 'Unauthorized Access') + create_preivew_badge_pdf(badgeForms) + file_path = file_pdf_path(badgeForms) + return send_from_directory('../', file_path, as_attachment=True) + + +@badge_forms_routes.route('/print-badge-pdf', methods=['POST']) +@jwt_required +def print_badge_pdf(): + attendee_id = request.json.get('attendee_id') + ticketHolders = TicketHolder.query.filter_by(id=attendee_id).first() + if ticketHolders is None: + raise NotFoundError( + {'source': ''}, 'This ticket holder is not associated with any ticket' + ) + badgeForms = BadgeForms.query.filter_by( + badge_id=ticketHolders.ticket.badge_id + ).first() + if badgeForms is None: + raise NotFoundError( + {'source': ''}, 'This badge form is not associated with any ticket' + ) + if not (has_access('is_coorganizer', event_id=badgeForms.event_id)): + raise ForbiddenError({'source': ''}, 'Unauthorized Access') + + create_print_badge_pdf(badgeForms, ticketHolders) + file_path = file_pdf_path(badgeForms) + return send_from_directory('../', file_path, as_attachment=True) diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py new file mode 100644 index 0000000000..3b76c21001 --- /dev/null +++ b/app/api/helpers/badge_forms.py @@ -0,0 +1,55 @@ +from flask import render_template +from flask_rest_jsonapi.exceptions import ObjectNotFound + +from app.api.helpers.files import create_save_pdf +from app.api.helpers.storage import UPLOAD_PATHS +from app.models.badge_field_form import BadgeFieldForms + + +def create_preivew_badge_pdf(badgeForms): + """ + Create tickets and invoices for the holders of an order. + :param badgeForms: The order for which to create tickets for. + """ + badgeFieldForms = ( + BadgeFieldForms.query.filter_by(badge_form_id=badgeForms.id) + .filter_by(badge_id=badgeForms.badge_id) + .all() + ) + return create_save_pdf( + render_template( + 'pdf/badge_forms.html', badgeForms=badgeForms, badgeFieldForms=badgeFieldForms + ), + UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=badgeForms.badge_id), + identifier=badgeForms.badge_id, + ) + + +def create_print_badge_pdf(badgeForms, ticketHolder): + """ + Create tickets and invoices for the holders of an order. + :param badgeForms: The order for which to create tickets for. + """ + badgeFieldForms = ( + BadgeFieldForms.query.filter_by(badge_form_id=badgeForms.id) + .filter_by(badge_id=badgeForms.badge_id) + .all() + ) + for field in badgeFieldForms: + try: + field.sample_text = getattr(ticketHolder, field.custom_field) + except AttributeError: + try: + field.sample_text = ticketHolder.complex_field_values[field.custom_field] + except AttributeError: + raise ObjectNotFound( + {'parameter': '{field.custom_field}'}, "Access Code: not found" + ) + + return create_save_pdf( + render_template( + 'pdf/badge_forms.html', badgeForms=badgeForms, badgeFieldForms=badgeFieldForms + ), + UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=badgeForms.badge_id), + identifier=badgeForms.badge_id, + ) diff --git a/app/api/helpers/storage.py b/app/api/helpers/storage.py index b12c2a5805..6562323d4f 100644 --- a/app/api/helpers/storage.py +++ b/app/api/helpers/storage.py @@ -77,6 +77,7 @@ 'order': 'orders/invoices/pdf/{identifier}', 'tickets_all': 'orders/tickets/pdf/{identifier}/{extra_identifier}', 'event_invoice': 'events/organizer/invoices/pdf/{event_identifier}/{identifier}', + 'badge_forms_pdf': 'badge-forms/generated-pdf/{identifier}', }, } diff --git a/app/instance.py b/app/instance.py index 55e33814ae..855f3d5c0c 100644 --- a/app/instance.py +++ b/app/instance.py @@ -169,6 +169,7 @@ def create_app(): from app.api.custom.group_role_invite import group_role_invites_routes from app.api.video_stream import streams_routes from app.api.events import events_blueprint + from app.api.custom.badge_forms import badge_forms_routes app.register_blueprint(api_v1) app.register_blueprint(event_copy) @@ -202,6 +203,7 @@ def create_app(): app.register_blueprint(events_blueprint) app.register_blueprint(tickets_routes) app.register_blueprint(group_role_invites_routes) + app.register_blueprint(badge_forms_routes) add_engine_pidguard(db.engine) diff --git a/app/templates/pdf/badge_forms.html b/app/templates/pdf/badge_forms.html new file mode 100644 index 0000000000..bea18ad9be --- /dev/null +++ b/app/templates/pdf/badge_forms.html @@ -0,0 +1,30 @@ + + + + + + + + +
+
+
+ {% for badgeFieldForm in badgeFieldForms %} + {% if badgeFieldForm.custom_field == 'QR' %} +
QR
+ {% else %} +

+ {{ badgeFieldForm.sample_text }} +

+ {% endif %} + {% endfor %} +
+
+
+ + \ No newline at end of file From 690babf5b033391b108c11a7bb4eb115704b3124 Mon Sep 17 00:00:00 2001 From: khangon Date: Thu, 13 Jul 2023 22:16:03 +0700 Subject: [PATCH 13/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_forms.py | 5 +++-- app/api/custom/schema/badge_form_field.py | 5 +++-- app/api/data_layers/BadgeFormLayer.py | 4 +++- app/api/schema/badge_field_forms.py | 3 ++- app/models/badge_field_form.py | 4 +++- ...44275_.py => rev-2023-07-13-18:04:51-2df361a9f0c3_.py} | 8 +++++--- 6 files changed, 19 insertions(+), 10 deletions(-) rename migrations/versions/{rev-2023-07-13-15:05:52-3f0debd44275_.py => rev-2023-07-13-18:04:51-2df361a9f0c3_.py} (93%) diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index 812dabbfee..bccaccdeae 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -120,6 +120,7 @@ def before_patch(_args, kwargs, data): badgeFieldForm.badge_id = data['badge_id'] badgeFieldForm.badge_form_id = kwargs['id'] + badgeFieldForm.field_identifier = badgeField['field_identifier'] badgeFieldForm.custom_field = badgeField['custom_field'] badgeFieldForm.sample_text = badgeField['sample_text'] badgeFieldForm.font_name = badgeField['font_name'] @@ -133,8 +134,8 @@ def before_patch(_args, kwargs, data): badgeFieldForm.margin_bottom = badgeField['margin_bottom'] badgeFieldForm.margin_left = badgeField['margin_left'] badgeFieldForm.margin_right = badgeField['margin_right'] - badgeFieldForm.qr_custom_field = badgeField['qr_custom_field'] - badgeFieldForm.is_deleted = False + badgeFieldForm.qr_custom_field = badgeField.get('qr_custom_field') + badgeFieldForm.is_deleted = badgeField['is_deleted'] db.session.add(badgeFieldForm) @staticmethod diff --git a/app/api/custom/schema/badge_form_field.py b/app/api/custom/schema/badge_form_field.py index f411ac8254..8df5c871a2 100644 --- a/app/api/custom/schema/badge_form_field.py +++ b/app/api/custom/schema/badge_form_field.py @@ -5,6 +5,7 @@ class BadgeFieldFormSchema(Schema): """Badge Field Form Schema""" badge_id = fields.String(allow_none=False) + field_identifier = fields.String(allow_none=True) custom_field = fields.String(allow_none=True) sample_text = fields.String(allow_none=True) font_size = fields.Integer(allow_none=True) @@ -15,9 +16,9 @@ class BadgeFieldFormSchema(Schema): text_alignment = fields.String(allow_none=True) text_type = fields.String(allow_none=True) id = fields.Integer(allow_none=True) - isDeleted = fields.Boolean(allow_none=True, default=False) + is_deleted = fields.Boolean(allow_none=True, default=False) margin_top = fields.Integer(allow_none=True) margin_bottom = fields.Integer(allow_none=True) margin_left = fields.Integer(allow_none=True) margin_right = fields.Integer(allow_none=True) - qr_custom_field = fields.List(fields.String(), allow_none=True) + qr_custom_field = fields.List(fields.String(), allow_none=True, default=None) diff --git a/app/api/data_layers/BadgeFormLayer.py b/app/api/data_layers/BadgeFormLayer.py index 0e6c723157..75bff04cd8 100644 --- a/app/api/data_layers/BadgeFormLayer.py +++ b/app/api/data_layers/BadgeFormLayer.py @@ -34,6 +34,7 @@ def create_object(data, _view_kwargs): if 'badge_fields' in data: keyBadgeFields = [ + 'field_identifier', 'custom_field', 'sample_text', 'font_size', @@ -48,6 +49,7 @@ def create_object(data, _view_kwargs): 'margin_left', 'margin_right', 'qr_custom_field', + 'is_deleted', ] for item in data['badge_fields']: badgeFieldForm = BadgeFieldForms() @@ -56,7 +58,7 @@ def create_object(data, _view_kwargs): badgeFieldForm.__setattr__(key, item[key]) badgeFieldForm.badge_id = item['badge_id'] - badgeFieldForm.is_deleted = item['isDeleted'] + badgeFieldForm.is_deleted = item['is_deleted'] badgeFieldForm.badge_form_id = badgeForm.id save_to_db(badgeFieldForm) return badgeForm diff --git a/app/api/schema/badge_field_forms.py b/app/api/schema/badge_field_forms.py index 0f809c4c23..dc12ca2ee8 100644 --- a/app/api/schema/badge_field_forms.py +++ b/app/api/schema/badge_field_forms.py @@ -27,12 +27,13 @@ class Meta: type_='badge_form', ) badge_id = fields.Str(required=True) + field_identifier = fields.String(required=False) custom_field = fields.String(required=False) sample_text = fields.String(required=False) font_size = fields.Integer(required=False) text_alignment = fields.String(required=False) text_type = fields.String(required=False) - isDeleted = fields.Boolean(required=False, default=False) + is_deleted = fields.Boolean(required=False, default=False) font_name = fields.String(required=False) font_weight = fields.Integer(required=False) font_color = fields.String(required=False) diff --git a/app/models/badge_field_form.py b/app/models/badge_field_form.py index 7ae3f283d0..adfa4ddb9c 100644 --- a/app/models/badge_field_form.py +++ b/app/models/badge_field_form.py @@ -13,6 +13,7 @@ class BadgeFieldForms(db.Model): 'BadgeForms', backref='badge_field_form', foreign_keys=[badge_form_id] ) badge_id = db.Column(db.String, nullable=False) + field_identifier = db.Column(db.String, nullable=True) custom_field = db.Column(db.String, nullable=True) sample_text = db.Column(db.String, nullable=True) font_size = db.Column(db.Integer, nullable=True) @@ -37,6 +38,7 @@ def convert_to_dict(self): """Convert object data to dictionary""" return { 'id': self.id, + 'field_identifier': self.field_identifier, 'custom_field': self.custom_field, 'sample_text': self.sample_text, 'badge_id': self.badge_id, @@ -47,7 +49,7 @@ def convert_to_dict(self): 'text_rotation': self.text_rotation, 'text_alignment': self.text_alignment, 'text_type': self.text_type, - 'isDeleted': self.is_deleted, + 'is_deleted': self.is_deleted, 'margin_top': self.margin_top, 'margin_bottom': self.margin_bottom, 'margin_left': self.margin_left, diff --git a/migrations/versions/rev-2023-07-13-15:05:52-3f0debd44275_.py b/migrations/versions/rev-2023-07-13-18:04:51-2df361a9f0c3_.py similarity index 93% rename from migrations/versions/rev-2023-07-13-15:05:52-3f0debd44275_.py rename to migrations/versions/rev-2023-07-13-18:04:51-2df361a9f0c3_.py index 835345d149..6ec35b724c 100644 --- a/migrations/versions/rev-2023-07-13-15:05:52-3f0debd44275_.py +++ b/migrations/versions/rev-2023-07-13-18:04:51-2df361a9f0c3_.py @@ -1,17 +1,18 @@ """empty message -Revision ID: 3f0debd44275 +Revision ID: 2df361a9f0c3 Revises: f508644acbd3 -Create Date: 2023-07-13 15:05:52.627311 +Create Date: 2023-07-13 18:04:51.453684 """ from alembic import op import sqlalchemy as sa +import sqlalchemy_utils from sqlalchemy.dialects import postgresql # revision identifiers, used by Alembic. -revision = '3f0debd44275' +revision = '2df361a9f0c3' down_revision = 'f508644acbd3' @@ -32,6 +33,7 @@ def upgrade(): sa.Column('id', sa.Integer(), nullable=False), sa.Column('badge_form_id', sa.Integer(), nullable=True), sa.Column('badge_id', sa.String(), nullable=False), + sa.Column('field_identifier', sa.String(), nullable=True), sa.Column('custom_field', sa.String(), nullable=True), sa.Column('sample_text', sa.String(), nullable=True), sa.Column('font_size', sa.Integer(), nullable=True), From 5991bf2fa3996570438a297d26410b7c7a98775e Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Fri, 14 Jul 2023 09:38:24 +0700 Subject: [PATCH 14/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_field_forms.py | 2 +- app/api/badge_forms.py | 5 +++++ app/api/routes.py | 1 + app/api/schema/badge_field_forms.py | 2 +- app/models/badge_field_form.py | 4 ++-- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/api/badge_field_forms.py b/app/api/badge_field_forms.py index 4c55daa125..294244c5d8 100644 --- a/app/api/badge_field_forms.py +++ b/app/api/badge_field_forms.py @@ -20,7 +20,7 @@ def query(self, view_kwargs): """ query_ = self.session.query(BadgeFieldForms) if view_kwargs.get('badge_form_id'): - query_ = query_.filter(badge_forms_id=view_kwargs['badge_form_id']) + query_ = query_.filter_by(badge_forms_id=view_kwargs['badge_form_id']) return query_ schema = BadgeFieldFormSchema diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index 812dabbfee..3723760445 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -13,6 +13,7 @@ from app.models.badge_field_form import BadgeFieldForms from app.models.badge_form import BadgeForms from app.models.event import Event +from app.models.ticket_holder import TicketHolder class BadgeFormList(ResourceList): @@ -29,6 +30,10 @@ def query(self, view_kwargs): events = safe_query_kwargs(Event, view_kwargs, 'event_id') query_ = self.session.query(BadgeForms).filter_by(event_id=events.id) query_ = query_.filter_by(badge_id=view_kwargs.get('badge_id')) + if view_kwargs.get('attendee_id'): + attendee = safe_query_kwargs(TicketHolder, view_kwargs, 'attendee_id') + badge_id_attendee = attendee.ticket.badge_id + query_ = query_.filter_by(badge_id=badge_id_attendee) else: query_ = event_query(query_, view_kwargs) return query_ diff --git a/app/api/routes.py b/app/api/routes.py index 310ba93e35..e086d808e8 100644 --- a/app/api/routes.py +++ b/app/api/routes.py @@ -2016,6 +2016,7 @@ api.route( BadgeFormList, 'badge_form_list', + '/attendees//badge-forms', '/events//badge-forms', '/events//badge-forms', '/events//badge-forms/', diff --git a/app/api/schema/badge_field_forms.py b/app/api/schema/badge_field_forms.py index e8145fd77d..b981a20fd3 100644 --- a/app/api/schema/badge_field_forms.py +++ b/app/api/schema/badge_field_forms.py @@ -12,7 +12,7 @@ class BadgeFieldFormSchema(Schema): class Meta: """Meta class for Badge Field Form Schema""" - type_ = 'custom-form-translate' + type_ = 'badge-field-form' self_view = 'v1.badge_field_form_detail' self_view_kwargs = {'id': ''} inflect = dasherize diff --git a/app/models/badge_field_form.py b/app/models/badge_field_form.py index 6c8a44a3c5..fd9d1fe0f0 100644 --- a/app/models/badge_field_form.py +++ b/app/models/badge_field_form.py @@ -9,7 +9,7 @@ class BadgeFieldForms(db.Model): db.Integer, db.ForeignKey('badge_forms.id', ondelete='CASCADE') ) badge_form = db.relationship( - 'BadgeForms', backref='badge_field_form', foreign_keys=[badge_form_id] + 'BadgeForms', backref='badge_field_forms_', foreign_keys=[badge_form_id] ) badge_id = db.Column(db.String, nullable=False) custom_field = db.Column(db.String, nullable=True) @@ -29,7 +29,7 @@ class BadgeFieldForms(db.Model): qr_custom_field = db.Column(db.String, nullable=True) def __repr__(self): - return f'' + return f'' def convert_to_dict(self): """Convert object data to dictionary""" From d32a06c2db5970e9e7e7fa898c47ffa7f2d88ad4 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Fri, 14 Jul 2023 14:12:54 +0700 Subject: [PATCH 15/37] feature-8683: Add Options for Badges in Wizard --- app/api/custom/badge_forms.py | 12 ++---------- app/api/helpers/badge_forms.py | 21 +++++++++++++++------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/app/api/custom/badge_forms.py b/app/api/custom/badge_forms.py index 99b93ca438..d87476f392 100644 --- a/app/api/custom/badge_forms.py +++ b/app/api/custom/badge_forms.py @@ -5,7 +5,6 @@ from app.api.helpers.badge_forms import create_preivew_badge_pdf, create_print_badge_pdf from app.api.helpers.errors import ForbiddenError, NotFoundError from app.api.helpers.permission_manager import has_access -from app.api.helpers.storage import UPLOAD_PATHS, generate_hash from app.models.badge_form import BadgeForms from app.models.ticket_holder import TicketHolder @@ -14,11 +13,6 @@ ) -def file_pdf_path(self) -> str: - key = UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=self.badge_id) - return f'static/media/{key}/{generate_hash(key)}/{self.badge_id}.pdf' - - @badge_forms_routes.route('/preivew-badge-pdf/') @jwt_required def preivew_badge_pdf(badge_id): @@ -30,8 +24,7 @@ def preivew_badge_pdf(badge_id): if not (has_access('is_coorganizer', event_id=badgeForms.event_id)): raise ForbiddenError({'source': ''}, 'Unauthorized Access') - create_preivew_badge_pdf(badgeForms) - file_path = file_pdf_path(badgeForms) + file_path = create_preivew_badge_pdf(badgeForms) return send_from_directory('../', file_path, as_attachment=True) @@ -54,6 +47,5 @@ def print_badge_pdf(): if not (has_access('is_coorganizer', event_id=badgeForms.event_id)): raise ForbiddenError({'source': ''}, 'Unauthorized Access') - create_print_badge_pdf(badgeForms, ticketHolders) - file_path = file_pdf_path(badgeForms) + file_path = create_print_badge_pdf(badgeForms, ticketHolders) return send_from_directory('../', file_path, as_attachment=True) diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py index 3b76c21001..d96cf3f637 100644 --- a/app/api/helpers/badge_forms.py +++ b/app/api/helpers/badge_forms.py @@ -2,10 +2,15 @@ from flask_rest_jsonapi.exceptions import ObjectNotFound from app.api.helpers.files import create_save_pdf -from app.api.helpers.storage import UPLOAD_PATHS +from app.api.helpers.storage import UPLOAD_PATHS, generate_hash from app.models.badge_field_form import BadgeFieldForms +def file_pdf_path(self) -> str: + key = UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=self.badge_id) + return f'static/media/{key}/{generate_hash(key)}/{self.badge_id}.pdf' + + def create_preivew_badge_pdf(badgeForms): """ Create tickets and invoices for the holders of an order. @@ -16,13 +21,14 @@ def create_preivew_badge_pdf(badgeForms): .filter_by(badge_id=badgeForms.badge_id) .all() ) - return create_save_pdf( + create_save_pdf( render_template( 'pdf/badge_forms.html', badgeForms=badgeForms, badgeFieldForms=badgeFieldForms ), UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=badgeForms.badge_id), identifier=badgeForms.badge_id, ) + return file_pdf_path(badgeForms) def create_print_badge_pdf(badgeForms, ticketHolder): @@ -37,19 +43,22 @@ def create_print_badge_pdf(badgeForms, ticketHolder): ) for field in badgeFieldForms: try: - field.sample_text = getattr(ticketHolder, field.custom_field) + field.sample_text = getattr(ticketHolder, field.field_identifier) except AttributeError: try: - field.sample_text = ticketHolder.complex_field_values[field.custom_field] + field.sample_text = ticketHolder.complex_field_values[ + field.field_identifier + ] except AttributeError: raise ObjectNotFound( - {'parameter': '{field.custom_field}'}, "Access Code: not found" + {'parameter': '{field.field_identifier}'}, "Access Code: not found" ) - return create_save_pdf( + create_save_pdf( render_template( 'pdf/badge_forms.html', badgeForms=badgeForms, badgeFieldForms=badgeFieldForms ), UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=badgeForms.badge_id), identifier=badgeForms.badge_id, ) + return file_pdf_path(badgeForms) From d5145f7187d9437f92b708aa909a10c0caddc61f Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Fri, 14 Jul 2023 15:39:18 +0700 Subject: [PATCH 16/37] feature-8683: Add Options for Badges in Wizard --- app/api/custom/badge_forms.py | 8 +++----- app/api/helpers/badge_forms.py | 14 ++++++-------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/app/api/custom/badge_forms.py b/app/api/custom/badge_forms.py index d87476f392..9c8ed3f703 100644 --- a/app/api/custom/badge_forms.py +++ b/app/api/custom/badge_forms.py @@ -13,17 +13,15 @@ ) -@badge_forms_routes.route('/preivew-badge-pdf/') +@badge_forms_routes.route('/preivew-badge-pdf', methods=['POST']) @jwt_required -def preivew_badge_pdf(badge_id): - badgeForms = BadgeForms.query.filter_by(badge_id=badge_id).first() +def preivew_badge_pdf(): + badgeForms = request.json.get('badgeForms') if badgeForms is None: raise NotFoundError( {'source': ''}, 'This badge form is not associated with any ticket' ) - if not (has_access('is_coorganizer', event_id=badgeForms.event_id)): - raise ForbiddenError({'source': ''}, 'Unauthorized Access') file_path = create_preivew_badge_pdf(badgeForms) return send_from_directory('../', file_path, as_attachment=True) diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py index d96cf3f637..20b8cdfab3 100644 --- a/app/api/helpers/badge_forms.py +++ b/app/api/helpers/badge_forms.py @@ -16,19 +16,17 @@ def create_preivew_badge_pdf(badgeForms): Create tickets and invoices for the holders of an order. :param badgeForms: The order for which to create tickets for. """ - badgeFieldForms = ( - BadgeFieldForms.query.filter_by(badge_form_id=badgeForms.id) - .filter_by(badge_id=badgeForms.badge_id) - .all() - ) + badgeFieldForms = badgeForms['badgeFields'] + badgeId = badgeForms['badgeID'] create_save_pdf( render_template( 'pdf/badge_forms.html', badgeForms=badgeForms, badgeFieldForms=badgeFieldForms ), - UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=badgeForms.badge_id), - identifier=badgeForms.badge_id, + UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=badgeId), + identifier=badgeId, ) - return file_pdf_path(badgeForms) + key = UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=badgeId) + return f'static/media/{key}/{generate_hash(key)}/{badgeId}.pdf' def create_print_badge_pdf(badgeForms, ticketHolder): From 99358731f5e32a2092db7d4b7fe35db34a0c366a Mon Sep 17 00:00:00 2001 From: khangon Date: Sun, 16 Jul 2023 15:53:01 +0700 Subject: [PATCH 17/37] feature-8683: Add Options for Badges in Wizard fix UI bug --- app/api/badge_forms.py | 8 ++++---- app/api/custom/schema/badge_form_field.py | 2 +- app/api/helpers/badge_forms.py | 1 + app/api/schema/badge_field_forms.py | 2 +- app/api/schema/events.py | 1 + app/models/event.py | 1 + ...c3_.py => rev-2023-07-16-15:45:05-2d3705de8180_.py} | 10 +++++++--- 7 files changed, 16 insertions(+), 9 deletions(-) rename migrations/versions/{rev-2023-07-13-18:04:51-2df361a9f0c3_.py => rev-2023-07-16-15:45:05-2d3705de8180_.py} (86%) diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index 5ec7ce2d59..d9a2fda59a 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -107,14 +107,14 @@ def before_patch(_args, kwargs, data): if badgeFields: for badgeField in badgeFields: badgeFieldForm = None - if 'id' in badgeField: + if 'badge_field_id' in badgeField: badgeFieldForm = BadgeFieldForms.check_badge_field_form( - kwargs['id'], badgeField['id'] + kwargs['id'], badgeField['badge_field_id'] ) if ( badgeFieldForm is not None - and 'isDeleted' in badgeField - and badgeField['isDeleted'] + and 'is_deleted' in badgeField + and badgeField['is_deleted'] ): db.session.delete(badgeFieldForm) else: diff --git a/app/api/custom/schema/badge_form_field.py b/app/api/custom/schema/badge_form_field.py index 8df5c871a2..e0c017b525 100644 --- a/app/api/custom/schema/badge_form_field.py +++ b/app/api/custom/schema/badge_form_field.py @@ -15,7 +15,7 @@ class BadgeFieldFormSchema(Schema): text_rotation = fields.Integer(allow_none=True) text_alignment = fields.String(allow_none=True) text_type = fields.String(allow_none=True) - id = fields.Integer(allow_none=True) + badge_field_id = fields.Integer(allow_none=True) is_deleted = fields.Boolean(allow_none=True, default=False) margin_top = fields.Integer(allow_none=True) margin_bottom = fields.Integer(allow_none=True) diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py index 20b8cdfab3..09b56c739a 100644 --- a/app/api/helpers/badge_forms.py +++ b/app/api/helpers/badge_forms.py @@ -16,6 +16,7 @@ def create_preivew_badge_pdf(badgeForms): Create tickets and invoices for the holders of an order. :param badgeForms: The order for which to create tickets for. """ + badgeForms = badgeForms[0] badgeFieldForms = badgeForms['badgeFields'] badgeId = badgeForms['badgeID'] create_save_pdf( diff --git a/app/api/schema/badge_field_forms.py b/app/api/schema/badge_field_forms.py index 249d287f6c..d4630161c7 100644 --- a/app/api/schema/badge_field_forms.py +++ b/app/api/schema/badge_field_forms.py @@ -17,7 +17,7 @@ class Meta: self_view_kwargs = {'id': ''} inflect = dasherize - id = fields.Integer(dump_only=True) + badge_field_id = fields.Integer(dump_only=True) badge_form = Relationship( self_view='v1.badge_field_form_badge_form', self_view_kwargs={'id': ''}, diff --git a/app/api/schema/events.py b/app/api/schema/events.py index 1e1a769f84..7167b2eadb 100644 --- a/app/api/schema/events.py +++ b/app/api/schema/events.py @@ -119,6 +119,7 @@ def validate_timezone(self, data, original_data): xcal_url = fields.Url(dump_only=True) refund_policy = fields.String(allow_none=True) is_stripe_linked = fields.Boolean(dump_only=True, allow_none=True, default=False) + is_badges_enabled = fields.Bool(default=True) tickets = Relationship( self_view='v1.event_ticket', diff --git a/app/models/event.py b/app/models/event.py index 24f8ee5ef9..b4f48c6a35 100644 --- a/app/models/event.py +++ b/app/models/event.py @@ -124,6 +124,7 @@ class Privacy: is_ticketing_enabled = db.Column(db.Boolean, default=False) is_donation_enabled = db.Column(db.Boolean, default=False) is_ticket_form_enabled = db.Column(db.Boolean, default=True, nullable=False) + is_badges_enabled = db.Column(db.Boolean, default=False) payment_country = db.Column(db.String) payment_currency = db.Column(db.String) paypal_email = db.Column(db.String) diff --git a/migrations/versions/rev-2023-07-13-18:04:51-2df361a9f0c3_.py b/migrations/versions/rev-2023-07-16-15:45:05-2d3705de8180_.py similarity index 86% rename from migrations/versions/rev-2023-07-13-18:04:51-2df361a9f0c3_.py rename to migrations/versions/rev-2023-07-16-15:45:05-2d3705de8180_.py index 6ec35b724c..2f8f923353 100644 --- a/migrations/versions/rev-2023-07-13-18:04:51-2df361a9f0c3_.py +++ b/migrations/versions/rev-2023-07-16-15:45:05-2d3705de8180_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: 2df361a9f0c3 +Revision ID: 2d3705de8180 Revises: f508644acbd3 -Create Date: 2023-07-13 18:04:51.453684 +Create Date: 2023-07-16 15:45:05.166587 """ @@ -12,7 +12,7 @@ from sqlalchemy.dialects import postgresql # revision identifiers, used by Alembic. -revision = '2df361a9f0c3' +revision = '2d3705de8180' down_revision = 'f508644acbd3' @@ -52,6 +52,8 @@ def upgrade(): sa.ForeignKeyConstraint(['badge_form_id'], ['badge_forms.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id') ) + op.add_column('events', sa.Column('is_badges_enabled', sa.Boolean(), nullable=True)) + op.add_column('events_version', sa.Column('is_badges_enabled', sa.Boolean(), autoincrement=False, nullable=True)) op.add_column('tickets', sa.Column('badge_id', sa.String(), nullable=True)) # ### end Alembic commands ### @@ -59,6 +61,8 @@ def upgrade(): def downgrade(): # ### commands auto generated by Alembic - please adjust! ### op.drop_column('tickets', 'badge_id') + op.drop_column('events_version', 'is_badges_enabled') + op.drop_column('events', 'is_badges_enabled') op.drop_table('badge_field_forms') op.drop_table('badge_forms') # ### end Alembic commands ### From a037aa6e5dd7d2223d936a7ba31158711a2e8771 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Mon, 17 Jul 2023 09:15:51 +0700 Subject: [PATCH 18/37] feature-8683: Add Options for Badges in Wizard --- app/models/badge_field_form.py | 7 ++++--- .../versions/rev-2023-07-16-15:45:05-2d3705de8180_.py | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/badge_field_form.py b/app/models/badge_field_form.py index 960bf384f8..72dece7f10 100644 --- a/app/models/badge_field_form.py +++ b/app/models/badge_field_form.py @@ -1,7 +1,9 @@ from sqlalchemy import String -from app.models import db from sqlalchemy.dialects.postgresql import ARRAY +from app.models import db + + class BadgeFieldForms(db.Model): """Badge Field Form database model""" @@ -28,8 +30,7 @@ class BadgeFieldForms(db.Model): margin_bottom = db.Column(db.Integer, nullable=True) margin_left = db.Column(db.Integer, nullable=True) margin_right = db.Column(db.Integer, nullable=True) - qr_custom_field = db.Column(ARRAY(String),nullable=True) - + qr_custom_field = db.Column(ARRAY(String), nullable=True) def __repr__(self): return f'' diff --git a/migrations/versions/rev-2023-07-16-15:45:05-2d3705de8180_.py b/migrations/versions/rev-2023-07-16-15:45:05-2d3705de8180_.py index 2f8f923353..885ddd03e0 100644 --- a/migrations/versions/rev-2023-07-16-15:45:05-2d3705de8180_.py +++ b/migrations/versions/rev-2023-07-16-15:45:05-2d3705de8180_.py @@ -8,7 +8,6 @@ from alembic import op import sqlalchemy as sa -import sqlalchemy_utils from sqlalchemy.dialects import postgresql # revision identifiers, used by Alembic. From 9df562f6eeb5f1b7d5cb49d327e23162243bfb30 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Mon, 17 Jul 2023 13:58:50 +0700 Subject: [PATCH 19/37] feature-8683: Add Options for Badges in Wizard --- app/api/custom/badge_forms.py | 6 +++++- app/api/helpers/badge_forms.py | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/api/custom/badge_forms.py b/app/api/custom/badge_forms.py index 9c8ed3f703..b72b80e8a7 100644 --- a/app/api/custom/badge_forms.py +++ b/app/api/custom/badge_forms.py @@ -16,6 +16,8 @@ @badge_forms_routes.route('/preivew-badge-pdf', methods=['POST']) @jwt_required def preivew_badge_pdf(): + """Preview Badge Template PDF""" + badgeForms = request.json.get('badgeForms') if badgeForms is None: raise NotFoundError( @@ -29,6 +31,8 @@ def preivew_badge_pdf(): @badge_forms_routes.route('/print-badge-pdf', methods=['POST']) @jwt_required def print_badge_pdf(): + """Print Badge PDF with information Attendee""" + attendee_id = request.json.get('attendee_id') ticketHolders = TicketHolder.query.filter_by(id=attendee_id).first() if ticketHolders is None: @@ -42,7 +46,7 @@ def print_badge_pdf(): raise NotFoundError( {'source': ''}, 'This badge form is not associated with any ticket' ) - if not (has_access('is_coorganizer', event_id=badgeForms.event_id)): + if not has_access('is_coorganizer', event_id=badgeForms.event_id): raise ForbiddenError({'source': ''}, 'Unauthorized Access') file_path = create_print_badge_pdf(badgeForms, ticketHolders) diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py index 09b56c739a..1933d49979 100644 --- a/app/api/helpers/badge_forms.py +++ b/app/api/helpers/badge_forms.py @@ -7,6 +7,8 @@ def file_pdf_path(self) -> str: + """Contructor path of File PDF""" + key = UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=self.badge_id) return f'static/media/{key}/{generate_hash(key)}/{self.badge_id}.pdf' From 6e3b299054278f2684f27dd6ba0a020861c6d384 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Mon, 17 Jul 2023 14:39:21 +0700 Subject: [PATCH 20/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_forms.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index d9a2fda59a..cf037e7280 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -189,7 +189,6 @@ def after_patch(badge_form): 'session': db.session, 'model': BadgeForms, 'methods': { - 'before_get_object': before_get_object, 'before_patch': before_patch, 'before_delete': before_delete, 'after_patch': after_patch, From 854b9a005557f4722e408b83e66048b61ded19dd Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Mon, 17 Jul 2023 17:39:48 +0700 Subject: [PATCH 21/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_forms.py | 3 +-- app/api/custom/schema/badge_form_field.py | 1 + app/models/badge_field_form.py | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index cf037e7280..98be2aa4b0 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -109,7 +109,7 @@ def before_patch(_args, kwargs, data): badgeFieldForm = None if 'badge_field_id' in badgeField: badgeFieldForm = BadgeFieldForms.check_badge_field_form( - kwargs['id'], badgeField['badge_field_id'] + badgeField['badge_field_id'], badgeField['badge_id'] ) if ( badgeFieldForm is not None @@ -165,7 +165,6 @@ def after_patch(badge_form): badgeFields = [] data = badge_form['data'] attributes = data['attributes'] - print(badge_form) badgeFieldForms = ( BadgeFieldForms.query.filter_by(badge_form_id=data['id']) .filter_by(badge_id=attributes['badge-id']) diff --git a/app/api/custom/schema/badge_form_field.py b/app/api/custom/schema/badge_form_field.py index e0c017b525..1d280ee362 100644 --- a/app/api/custom/schema/badge_form_field.py +++ b/app/api/custom/schema/badge_form_field.py @@ -4,6 +4,7 @@ class BadgeFieldFormSchema(Schema): """Badge Field Form Schema""" + badge_field_id = fields.Integer(allow_none=False) badge_id = fields.String(allow_none=False) field_identifier = fields.String(allow_none=True) custom_field = fields.String(allow_none=True) diff --git a/app/models/badge_field_form.py b/app/models/badge_field_form.py index 72dece7f10..7325949a15 100644 --- a/app/models/badge_field_form.py +++ b/app/models/badge_field_form.py @@ -59,17 +59,17 @@ def convert_to_dict(self): } @staticmethod - def check_badge_field_form(badge_form_id, badge_field_form_id): + def check_badge_field_form(id, badge_id): """ check custom form translate - :param badge_form_id: - :param badge_field_form_id: + :param id: + :param badge_id: :return: """ try: badgeFieldForm = ( - BadgeFieldForms.query.filter_by(badge_form_id=badge_form_id) - .filter_by(id=badge_field_form_id) + BadgeFieldForms.query.filter_by(badge_id=badge_id) + .filter_by(id=id) .first() ) return badgeFieldForm From 725685e1eb3e308e04f90cd3453cdb51fb4b8ee5 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Tue, 18 Jul 2023 09:00:07 +0700 Subject: [PATCH 22/37] thanhhieu-tma/feature-8683: Add print QR code --- app/api/helpers/badge_forms.py | 101 ++++++++++++++---- app/templates/cvf/badge_qr_template.cvf | 133 ++++++++++++++++++++++++ app/templates/pdf/badge_forms.html | 4 +- 3 files changed, 218 insertions(+), 20 deletions(-) create mode 100644 app/templates/cvf/badge_qr_template.cvf diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py index 1933d49979..e83abc8d9b 100644 --- a/app/api/helpers/badge_forms.py +++ b/app/api/helpers/badge_forms.py @@ -1,9 +1,16 @@ +import base64 +import io + +import qrcode from flask import render_template -from flask_rest_jsonapi.exceptions import ObjectNotFound +from sqlalchemy import asc from app.api.helpers.files import create_save_pdf from app.api.helpers.storage import UPLOAD_PATHS, generate_hash +from app.api.helpers.utilities import to_snake_case from app.models.badge_field_form import BadgeFieldForms +from app.models.custom_form import CustomForms +from app.models.ticket_holder import TicketHolder def file_pdf_path(self) -> str: @@ -32,34 +39,90 @@ def create_preivew_badge_pdf(badgeForms): return f'static/media/{key}/{generate_hash(key)}/{badgeId}.pdf' -def create_print_badge_pdf(badgeForms, ticketHolder): +def get_value_from_field_indentifier(field: BadgeFieldForms, ticket_holder: TicketHolder): + try: + field.sample_text = getattr(ticket_holder, field.field_identifier) or '' + except AttributeError: + try: + field.sample_text = ( + ticket_holder.complex_field_values[field.field_identifier] or '' + ) + except AttributeError: + print(f"get_value_from_field_indentifier ===={field.field_identifier}") + + +def get_value_from_qr_filed(field: BadgeFieldForms, ticket_holder: TicketHolder) -> dict: + qr_value = {} + custom_fields = [] + for field_identifier in field.qr_custom_field: + value_ = "" + try: + snake_case_field_identifier = to_snake_case(field_identifier) + value_ = getattr(ticket_holder, snake_case_field_identifier) + except AttributeError: + try: + value_ = ticket_holder.complex_field_values[field_identifier] + # Get the field description then Capitalize first letter and remove space. + custom_form = CustomForms.query.filter_by( + field_identifier=field_identifier, + form_id=ticket_holder.ticket_id.form_id, + ).first() + field_description = custom_form.description.title().replace(' ', '') + custom_fields.append({field_description: value_}) + except AttributeError: + print(field_identifier) + + qr_value.update({field_identifier: str(value_)}) + qr_value.update( + {'custom_fields': custom_fields, 'ticket_id': ticket_holder.ticket_id} + ) + return qr_value + + +def create_base64_img_qr(qr_code_data: str) -> str: + qr = qrcode.QRCode( + version=1, + error_correction=qrcode.constants.ERROR_CORRECT_L, + box_size=10, + border=2, + ) + qr.add_data(qr_code_data) + qr.make(fit=True) + img = qr.make_image(fill_color="black", back_color="white") + io_buffer = io.BytesIO() + img.save(io_buffer) + qr_img_str = base64.b64encode(io_buffer.getvalue()).decode() + return qr_img_str + + +def create_print_badge_pdf(badge_form, ticket_holder): """ Create tickets and invoices for the holders of an order. :param badgeForms: The order for which to create tickets for. """ badgeFieldForms = ( - BadgeFieldForms.query.filter_by(badge_form_id=badgeForms.id) - .filter_by(badge_id=badgeForms.badge_id) + BadgeFieldForms.query.filter_by(badge_form_id=badge_form.id) + .filter_by(badge_id=badge_form.badge_id) + .order_by(asc("id")) .all() ) for field in badgeFieldForms: - try: - field.sample_text = getattr(ticketHolder, field.field_identifier) - except AttributeError: - try: - field.sample_text = ticketHolder.complex_field_values[ - field.field_identifier - ] - except AttributeError: - raise ObjectNotFound( - {'parameter': '{field.field_identifier}'}, "Access Code: not found" - ) + # if field not in list_field_show: + # field.sample_text = " " + # continue + if field.custom_field.lower() == 'qr': + # for field_identifier_ in field.qr_custom_field: + qr_code_data = get_value_from_qr_filed(field, ticket_holder) + qr_rendered = render_template('cvf/badge_qr_template.cvf', **qr_code_data) + field.sample_text = create_base64_img_qr(qr_rendered) + continue + get_value_from_field_indentifier(field, ticket_holder) create_save_pdf( render_template( - 'pdf/badge_forms.html', badgeForms=badgeForms, badgeFieldForms=badgeFieldForms + 'pdf/badge_forms.html', badgeForms=badge_form, badgeFieldForms=badgeFieldForms ), - UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=badgeForms.badge_id), - identifier=badgeForms.badge_id, + UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=badge_form.badge_id), + identifier=badge_form.badge_id, ) - return file_pdf_path(badgeForms) + return file_pdf_path(badge_form) diff --git a/app/templates/cvf/badge_qr_template.cvf b/app/templates/cvf/badge_qr_template.cvf new file mode 100644 index 0000000000..ffae605e98 --- /dev/null +++ b/app/templates/cvf/badge_qr_template.cvf @@ -0,0 +1,133 @@ +BEGIN:VCARD + +VERSION:3.0 + +X-SOCIALPROFILE;TYPE=EVENTYAY:{{ ticket_id }} + +EMAIL:{{ email }} +{% if firstname or lastname %} +FN:{{ firstname|default('') }} {{ lastname|default('') }} + +N:{{ lastname|default('') }};{{ firstname|default('') }};;; +{% endif %} + +{% if phone %} +TEL;TYPE=HOME:{{ phone }} +{% endif %} + +{% if workPhone %} +TEL;TYPE=WORK:{{ workPhone }} +{% endif %} + +{% if address or city or state or country %} +ADR;TYPE=ADDRESS:;;{{ address }};{{city|default('')}};{{state|default('')}};;{{country|default('')}} +{% endif %} + +{% if billingAddress %} +ADR;TYPE=BILLING:;;{{billingAddress}};;;; +{% endif %} + +{% if homeAddress %} +ADR;TYPE=HOME:;;{{homeAddress}};;;; +{% endif %} + +{% if shippingAddress %} +ADR;TYPE=SHIPPING:;;{{shippingAddress}};;;; +{% endif %} + +{% if workAddress %} +ADR;TYPE=WORK:;;{{workAddress}};;;; +{% endif %} + +{% if company %} +ORG:{{company}} +{% endif %} + +{% if jobTitle %} +ORG:{{jobTitle}} +{% endif %} + +{% if website %} +URL;TYPE=WEBSITE:{{website}} +{% endif %} + +{% if blog %} +URL;TYPE=BLOG:{{blog}} +{% endif %} + +{% if twitter %} +URL;TYPE=TWITTER:{{twitter}} +{% endif %} + +{% if facebook %} +URL;TYPE=FACEBOK:{{facebook}} +{% endif %} + +{% if github %} +URL;TYPE=GITHUB:{{github}} +{% endif %} + +{% if linkedin %} +URL;TYPE=LINIKENDIN:{{linkedin}} +{% endif %} + +{% if instagram %} +URL;TYPE=INSTAGRAM:{{instagram}} +{% endif %} + +{% if gender %} +X-SOCIALPROFILE;TYPE=GENDER:{{gender}} +{% endif %} + +{% if ageGroup %} +X-SOCIALPROFILE;TYPE=AGEGROUP:{{ageGroup}} +{% endif %} + +{% if acceptVideoRecording %} +X-SOCIALPROFILE;TYPE=ACCEPTVIDEORECORDING:{{acceptVideoRecording}} +{% endif %} + +{% if acceptShareDetails %} +X-SOCIALPROFILE;TYPE=ACCEPTSHAREDETAILS:{{acceptShareDetails}} +{% endif %} + +{% if acceptReceiveEmails %} +X-SOCIALPROFILE;TYPE=ACCEPTRECEIVEEMAILS:{{acceptReceiveEmails}} +{% endif %} + +{% if is_consent_form_field %} +X-SOCIALPROFILE;TYPE=ConsentFormField:{{is_consent_form_field}} +{% endif %} + +{% if is_consent_form_field_photo %} +X-SOCIALPROFILE;TYPE=ConsentFormFieldPhoto:{{is_consent_form_field_photo}} +{% endif %} + +{% if is_consent_of_refund_policy %} +X-SOCIALPROFILE;TYPE=ConsentOfRefundPolicy:{{is_consent_of_refund_policy}} +{% endif %} + +{% if native_language %} +X-SOCIALPROFILE;TYPE=NativeLanguage:{{native_language}} +{% endif %} + +{% if fluent_language %} +X-SOCIALPROFILE;TYPE=FluentLanguage:{{fluent_language}} +{% endif %} + +{% if home_wiki %} +X-SOCIALPROFILE;TYPE=HomeWiki:{{home_wiki}} +{% endif %} + +{% if wiki_scholarship %} +X-SOCIALPROFILE;TYPE=WikiScholarship:{{wiki_scholarship}} +{% endif %} + +{% for custom_field in custom_fields %} +{% for key, value in custom_field.items() %} +X-SOCIALPROFILE;TYPE={{key}}:{{value}} +{% endfor %} +{% endfor %} + +END:VCARD + diff --git a/app/templates/pdf/badge_forms.html b/app/templates/pdf/badge_forms.html index bea18ad9be..8568f3d4c1 100644 --- a/app/templates/pdf/badge_forms.html +++ b/app/templates/pdf/badge_forms.html @@ -12,7 +12,9 @@
{% for badgeFieldForm in badgeFieldForms %} {% if badgeFieldForm.custom_field == 'QR' %} -
QR
+
+ QR +
{% else %}

Date: Tue, 18 Jul 2023 16:26:26 +0700 Subject: [PATCH 24/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_forms.py | 5 --- app/api/custom/badge_forms.py | 3 +- app/api/custom/tickets.py | 32 +++++++++++++++ app/api/helpers/badge_forms.py | 21 ++++++---- app/api/routes.py | 1 - app/api/schema/attendees.py | 7 +++- app/instance.py | 2 + app/models/badge_field_form.py | 8 ++++ app/models/ticket_holder.py | 6 ++- app/templates/pdf/badge_forms.html | 20 +++++++-- .../rev-2023-07-18-15:27:36-2b19596af9f0_.py | 41 +++++++++++++++++++ 11 files changed, 125 insertions(+), 21 deletions(-) create mode 100644 app/api/custom/tickets.py create mode 100644 migrations/versions/rev-2023-07-18-15:27:36-2b19596af9f0_.py diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index 98be2aa4b0..a8ba3ebf6d 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -13,7 +13,6 @@ from app.models.badge_field_form import BadgeFieldForms from app.models.badge_form import BadgeForms from app.models.event import Event -from app.models.ticket_holder import TicketHolder class BadgeFormList(ResourceList): @@ -30,10 +29,6 @@ def query(self, view_kwargs): events = safe_query_kwargs(Event, view_kwargs, 'event_id') query_ = self.session.query(BadgeForms).filter_by(event_id=events.id) query_ = query_.filter_by(badge_id=view_kwargs.get('badge_id')) - if view_kwargs.get('attendee_id'): - attendee = safe_query_kwargs(TicketHolder, view_kwargs, 'attendee_id') - badge_id_attendee = attendee.ticket.badge_id - query_ = query_.filter_by(badge_id=badge_id_attendee) else: query_ = event_query(query_, view_kwargs) return query_ diff --git a/app/api/custom/badge_forms.py b/app/api/custom/badge_forms.py index b72b80e8a7..0b626870b8 100644 --- a/app/api/custom/badge_forms.py +++ b/app/api/custom/badge_forms.py @@ -34,6 +34,7 @@ def print_badge_pdf(): """Print Badge PDF with information Attendee""" attendee_id = request.json.get('attendee_id') + list_field_show = request.json.get('list_field_show') ticketHolders = TicketHolder.query.filter_by(id=attendee_id).first() if ticketHolders is None: raise NotFoundError( @@ -49,5 +50,5 @@ def print_badge_pdf(): if not has_access('is_coorganizer', event_id=badgeForms.event_id): raise ForbiddenError({'source': ''}, 'Unauthorized Access') - file_path = create_print_badge_pdf(badgeForms, ticketHolders) + file_path = create_print_badge_pdf(badgeForms, ticketHolders, list_field_show) return send_from_directory('../', file_path, as_attachment=True) diff --git a/app/api/custom/tickets.py b/app/api/custom/tickets.py new file mode 100644 index 0000000000..1218fbd006 --- /dev/null +++ b/app/api/custom/tickets.py @@ -0,0 +1,32 @@ +from flask import Blueprint, jsonify +from flask_jwt_extended import jwt_required + +from app.api.helpers.errors import NotFoundError +from app.models.badge_field_form import BadgeFieldForms +from app.models.ticket import Ticket + +ticket_routes = Blueprint('ticket_routes', __name__, url_prefix='/v1/tickets') + + +@ticket_routes.route('//badge-forms', methods=['GET']) +@jwt_required +def get_badge_field(ticket_id): + """Get Badge Field""" + + ticket = Ticket.query.filter_by(id=ticket_id).first() + if ticket is None: + raise NotFoundError( + {'source': ''}, 'This ticket holder is not associated with any ticket' + ) + + badgeFieldForms = BadgeFieldForms.query.filter_by(badge_id=ticket.badge_id).all() + if badgeFieldForms is None: + raise NotFoundError( + {'source': ''}, 'This badge field form is not associated with any ticket' + ) + + result = [] + for badgeFieldForm in badgeFieldForms: + result.append(badgeFieldForm.convert_to_dict_by_ticket()) + + return jsonify(result) diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py index e83abc8d9b..ee1b84b3ab 100644 --- a/app/api/helpers/badge_forms.py +++ b/app/api/helpers/badge_forms.py @@ -1,10 +1,12 @@ import base64 import io +from datetime import datetime import qrcode from flask import render_template from sqlalchemy import asc +from app.api.helpers.db import save_to_db from app.api.helpers.files import create_save_pdf from app.api.helpers.storage import UPLOAD_PATHS, generate_hash from app.api.helpers.utilities import to_snake_case @@ -40,15 +42,16 @@ def create_preivew_badge_pdf(badgeForms): def get_value_from_field_indentifier(field: BadgeFieldForms, ticket_holder: TicketHolder): + snake_case_field_identifier = to_snake_case(field.field_identifier) try: - field.sample_text = getattr(ticket_holder, field.field_identifier) or '' + field.sample_text = getattr(ticket_holder, snake_case_field_identifier) or '' except AttributeError: try: field.sample_text = ( - ticket_holder.complex_field_values[field.field_identifier] or '' + ticket_holder.complex_field_values[snake_case_field_identifier] or '' ) except AttributeError: - print(f"get_value_from_field_indentifier ===={field.field_identifier}") + print(f"get_value_from_field_indentifier ===={snake_case_field_identifier}") def get_value_from_qr_filed(field: BadgeFieldForms, ticket_holder: TicketHolder) -> dict: @@ -95,7 +98,7 @@ def create_base64_img_qr(qr_code_data: str) -> str: return qr_img_str -def create_print_badge_pdf(badge_form, ticket_holder): +def create_print_badge_pdf(badge_form, ticket_holder, list_field_show): """ Create tickets and invoices for the holders of an order. :param badgeForms: The order for which to create tickets for. @@ -107,9 +110,6 @@ def create_print_badge_pdf(badge_form, ticket_holder): .all() ) for field in badgeFieldForms: - # if field not in list_field_show: - # field.sample_text = " " - # continue if field.custom_field.lower() == 'qr': # for field_identifier_ in field.qr_custom_field: qr_code_data = get_value_from_qr_filed(field, ticket_holder) @@ -117,6 +117,10 @@ def create_print_badge_pdf(badge_form, ticket_holder): field.sample_text = create_base64_img_qr(qr_rendered) continue + elif list_field_show is None or field.field_identifier not in list_field_show: + field.sample_text = ' ' + continue + get_value_from_field_indentifier(field, ticket_holder) create_save_pdf( render_template( @@ -125,4 +129,7 @@ def create_print_badge_pdf(badge_form, ticket_holder): UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=badge_form.badge_id), identifier=badge_form.badge_id, ) + ticket_holder.is_badge_printed = True + ticket_holder.badge_printed_at = datetime.now() + save_to_db(ticket_holder, 'Ticket Holder saved') return file_pdf_path(badge_form) diff --git a/app/api/routes.py b/app/api/routes.py index e086d808e8..310ba93e35 100644 --- a/app/api/routes.py +++ b/app/api/routes.py @@ -2016,7 +2016,6 @@ api.route( BadgeFormList, 'badge_form_list', - '/attendees//badge-forms', '/events//badge-forms', '/events//badge-forms', '/events//badge-forms/', diff --git a/app/api/schema/attendees.py b/app/api/schema/attendees.py index c5bcda44f7..06eaebfa45 100644 --- a/app/api/schema/attendees.py +++ b/app/api/schema/attendees.py @@ -29,8 +29,8 @@ def validate_json(self, data, original_data): validate_complex_fields_json(self, data, original_data) id = fields.Str(dump_only=True) - firstname = fields.Str(required=True) - lastname = fields.Str(required=True) + firstname = fields.Str(allow_none=True) + lastname = fields.Str(allow_none=True) email = TrimmedEmail(allow_none=True) address = fields.Str(allow_none=True) city = fields.Str(allow_none=True) @@ -62,6 +62,7 @@ def validate_json(self, data, original_data): home_wiki = fields.Str(allow_none=True) wiki_scholarship = fields.Str(allow_none=True) birth_date = fields.DateTime(allow_none=True) + modified_at = fields.DateTime(allow_none=True) ticket_id = fields.Str(allow_none=True) is_checked_in = fields.Boolean() @@ -78,6 +79,8 @@ def validate_json(self, data, original_data): fluent_language = fields.Str(allow_none=True) is_consent_form_field_photo = fields.Boolean(allow_none=True) is_consent_form_field_email = fields.Boolean(allow_none=True) + is_badge_printed = fields.Boolean(allow_none=True) + badge_printed_at = fields.DateTime(allow_none=True) event = Relationship( self_view='v1.attendee_event', self_view_kwargs={'id': ''}, diff --git a/app/instance.py b/app/instance.py index 855f3d5c0c..eb8db3e18a 100644 --- a/app/instance.py +++ b/app/instance.py @@ -170,6 +170,7 @@ def create_app(): from app.api.video_stream import streams_routes from app.api.events import events_blueprint from app.api.custom.badge_forms import badge_forms_routes + from app.api.custom.tickets import ticket_routes app.register_blueprint(api_v1) app.register_blueprint(event_copy) @@ -204,6 +205,7 @@ def create_app(): app.register_blueprint(tickets_routes) app.register_blueprint(group_role_invites_routes) app.register_blueprint(badge_forms_routes) + app.register_blueprint(ticket_routes) add_engine_pidguard(db.engine) diff --git a/app/models/badge_field_form.py b/app/models/badge_field_form.py index dfc5dc66cd..a0277dec28 100644 --- a/app/models/badge_field_form.py +++ b/app/models/badge_field_form.py @@ -58,6 +58,14 @@ def convert_to_dict(self): 'qr_custom_field': self.qr_custom_field, } + def convert_to_dict_by_ticket(self): + """Convert object data to dictionary""" + return { + 'id': self.id, + 'field_identifier': self.field_identifier, + 'custom_field': self.custom_field, + } + @staticmethod def check_badge_field_form(badge_field_id, badge_id): """ diff --git a/app/models/ticket_holder.py b/app/models/ticket_holder.py index da53a11a68..3c956428c1 100644 --- a/app/models/ticket_holder.py +++ b/app/models/ticket_holder.py @@ -16,8 +16,8 @@ class TicketHolder(SoftDeletionModel): __tablename__ = "ticket_holders" id: int = db.Column(db.Integer, primary_key=True) - firstname: str = db.Column(db.String, nullable=False) - lastname: str = db.Column(db.String, nullable=False) + firstname: str = db.Column(db.String) + lastname: str = db.Column(db.String) email: str = db.Column(CIText) address: str = db.Column(db.String) city: str = db.Column(db.String) @@ -82,6 +82,8 @@ class TicketHolder(SoftDeletionModel): is_consent_form_field: bool = db.Column(db.Boolean, default=False) is_consent_form_field_photo: bool = db.Column(db.Boolean, default=False) is_consent_form_field_email: bool = db.Column(db.Boolean, default=False) + is_badge_printed: bool = db.Column(db.Boolean, default=False) + badge_printed_at: datetime = db.Column(db.DateTime(timezone=True)) @property def name(self): diff --git a/app/templates/pdf/badge_forms.html b/app/templates/pdf/badge_forms.html index 8568f3d4c1..41b08b1549 100644 --- a/app/templates/pdf/badge_forms.html +++ b/app/templates/pdf/badge_forms.html @@ -12,14 +12,28 @@

{% for badgeFieldForm in badgeFieldForms %} {% if badgeFieldForm.custom_field == 'QR' %} -
+
QR
{% else %}

{{ badgeFieldForm.sample_text }}

diff --git a/migrations/versions/rev-2023-07-18-15:27:36-2b19596af9f0_.py b/migrations/versions/rev-2023-07-18-15:27:36-2b19596af9f0_.py new file mode 100644 index 0000000000..cc0cf7e896 --- /dev/null +++ b/migrations/versions/rev-2023-07-18-15:27:36-2b19596af9f0_.py @@ -0,0 +1,41 @@ +"""empty message + +Revision ID: 2b19596af9f0 +Revises: 2d3705de8180 +Create Date: 2023-07-18 15:27:36.059991 + +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '2b19596af9f0' +down_revision = '2d3705de8180' + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('ticket_holders', sa.Column('is_badge_printed', sa.Boolean(), nullable=True)) + op.add_column('ticket_holders', sa.Column('badge_printed_at', sa.DateTime(timezone=True), nullable=True)) + op.alter_column('ticket_holders', 'firstname', + existing_type=sa.VARCHAR(), + nullable=True) + op.alter_column('ticket_holders', 'lastname', + existing_type=sa.VARCHAR(), + nullable=True) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column('ticket_holders', 'lastname', + existing_type=sa.VARCHAR(), + nullable=False) + op.alter_column('ticket_holders', 'firstname', + existing_type=sa.VARCHAR(), + nullable=False) + op.drop_column('ticket_holders', 'badge_printed_at') + op.drop_column('ticket_holders', 'is_badge_printed') + # ### end Alembic commands ### From 9a1044b7de882d1b870957cec5d3d8dbd4a5bd39 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Tue, 18 Jul 2023 17:01:36 +0700 Subject: [PATCH 25/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_forms.py | 2 +- app/api/custom/tickets.py | 2 +- app/api/helpers/badge_forms.py | 3 +-- app/api/schema/attendees.py | 1 - app/models/badge_field_form.py | 6 +++--- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index a8ba3ebf6d..08897999a0 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -103,7 +103,7 @@ def before_patch(_args, kwargs, data): for badgeField in badgeFields: badgeFieldForm = None if 'badge_field_id' in badgeField: - badgeFieldForm = BadgeFieldForms.check_badge_field_form( + badgeFieldForm = BadgeFieldForms.get_badge_field_form_if_exist( badgeField['badge_field_id'], badgeField['badge_id'] ) if ( diff --git a/app/api/custom/tickets.py b/app/api/custom/tickets.py index 1218fbd006..4d86bbf880 100644 --- a/app/api/custom/tickets.py +++ b/app/api/custom/tickets.py @@ -27,6 +27,6 @@ def get_badge_field(ticket_id): result = [] for badgeFieldForm in badgeFieldForms: - result.append(badgeFieldForm.convert_to_dict_by_ticket()) + result.append(badgeFieldForm.get_badge_field()) return jsonify(result) diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py index ee1b84b3ab..88a6f82ff9 100644 --- a/app/api/helpers/badge_forms.py +++ b/app/api/helpers/badge_forms.py @@ -111,13 +111,12 @@ def create_print_badge_pdf(badge_form, ticket_holder, list_field_show): ) for field in badgeFieldForms: if field.custom_field.lower() == 'qr': - # for field_identifier_ in field.qr_custom_field: qr_code_data = get_value_from_qr_filed(field, ticket_holder) qr_rendered = render_template('cvf/badge_qr_template.cvf', **qr_code_data) field.sample_text = create_base64_img_qr(qr_rendered) continue - elif list_field_show is None or field.field_identifier not in list_field_show: + if list_field_show is None or field.field_identifier not in list_field_show: field.sample_text = ' ' continue diff --git a/app/api/schema/attendees.py b/app/api/schema/attendees.py index 06eaebfa45..c74a78962a 100644 --- a/app/api/schema/attendees.py +++ b/app/api/schema/attendees.py @@ -62,7 +62,6 @@ def validate_json(self, data, original_data): home_wiki = fields.Str(allow_none=True) wiki_scholarship = fields.Str(allow_none=True) birth_date = fields.DateTime(allow_none=True) - modified_at = fields.DateTime(allow_none=True) ticket_id = fields.Str(allow_none=True) is_checked_in = fields.Boolean() diff --git a/app/models/badge_field_form.py b/app/models/badge_field_form.py index a0277dec28..19932477cd 100644 --- a/app/models/badge_field_form.py +++ b/app/models/badge_field_form.py @@ -58,8 +58,8 @@ def convert_to_dict(self): 'qr_custom_field': self.qr_custom_field, } - def convert_to_dict_by_ticket(self): - """Convert object data to dictionary""" + def get_badge_field(self): + """Support for only api from ticket #8982""" return { 'id': self.id, 'field_identifier': self.field_identifier, @@ -67,7 +67,7 @@ def convert_to_dict_by_ticket(self): } @staticmethod - def check_badge_field_form(badge_field_id, badge_id): + def get_badge_field_form_if_exist(badge_field_id, badge_id): """ check custom form translate :param badge_field_id: From ed7f14ff3d633ad540c8db043f02cf923b72b383 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Tue, 18 Jul 2023 17:05:34 +0700 Subject: [PATCH 26/37] feature-8683: Add Options for Badges in Wizard --- app/api/custom/badge_forms.py | 4 +--- app/api/custom/tickets.py | 1 - app/api/helpers/badge_forms.py | 4 +++- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/api/custom/badge_forms.py b/app/api/custom/badge_forms.py index 0b626870b8..4af5b7e3a6 100644 --- a/app/api/custom/badge_forms.py +++ b/app/api/custom/badge_forms.py @@ -17,7 +17,6 @@ @jwt_required def preivew_badge_pdf(): """Preview Badge Template PDF""" - badgeForms = request.json.get('badgeForms') if badgeForms is None: raise NotFoundError( @@ -31,8 +30,7 @@ def preivew_badge_pdf(): @badge_forms_routes.route('/print-badge-pdf', methods=['POST']) @jwt_required def print_badge_pdf(): - """Print Badge PDF with information Attendee""" - + """Print Badge Template PDF""" attendee_id = request.json.get('attendee_id') list_field_show = request.json.get('list_field_show') ticketHolders = TicketHolder.query.filter_by(id=attendee_id).first() diff --git a/app/api/custom/tickets.py b/app/api/custom/tickets.py index 4d86bbf880..32a568e75d 100644 --- a/app/api/custom/tickets.py +++ b/app/api/custom/tickets.py @@ -12,7 +12,6 @@ @jwt_required def get_badge_field(ticket_id): """Get Badge Field""" - ticket = Ticket.query.filter_by(id=ticket_id).first() if ticket is None: raise NotFoundError( diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py index 88a6f82ff9..d69651043f 100644 --- a/app/api/helpers/badge_forms.py +++ b/app/api/helpers/badge_forms.py @@ -17,7 +17,6 @@ def file_pdf_path(self) -> str: """Contructor path of File PDF""" - key = UPLOAD_PATHS['pdf']['badge_forms_pdf'].format(identifier=self.badge_id) return f'static/media/{key}/{generate_hash(key)}/{self.badge_id}.pdf' @@ -42,6 +41,7 @@ def create_preivew_badge_pdf(badgeForms): def get_value_from_field_indentifier(field: BadgeFieldForms, ticket_holder: TicketHolder): + """Get the value of a field.""" snake_case_field_identifier = to_snake_case(field.field_identifier) try: field.sample_text = getattr(ticket_holder, snake_case_field_identifier) or '' @@ -55,6 +55,7 @@ def get_value_from_field_indentifier(field: BadgeFieldForms, ticket_holder: Tick def get_value_from_qr_filed(field: BadgeFieldForms, ticket_holder: TicketHolder) -> dict: + """Get the value of a QR code field.""" qr_value = {} custom_fields = [] for field_identifier in field.qr_custom_field: @@ -83,6 +84,7 @@ def get_value_from_qr_filed(field: BadgeFieldForms, ticket_holder: TicketHolder) def create_base64_img_qr(qr_code_data: str) -> str: + """Create a base64 image of a QR code.""" qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, From 674dd9f12eb16c75995500c19a47fc77200b383b Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Tue, 18 Jul 2023 17:07:33 +0700 Subject: [PATCH 27/37] feature-8683: Add Options for Badges in Wizard --- app/api/helpers/badge_forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py index d69651043f..8e010d67e7 100644 --- a/app/api/helpers/badge_forms.py +++ b/app/api/helpers/badge_forms.py @@ -69,7 +69,7 @@ def get_value_from_qr_filed(field: BadgeFieldForms, ticket_holder: TicketHolder) # Get the field description then Capitalize first letter and remove space. custom_form = CustomForms.query.filter_by( field_identifier=field_identifier, - form_id=ticket_holder.ticket_id.form_id, + form_id=ticket_holder.ticket.form_id, ).first() field_description = custom_form.description.title().replace(' ', '') custom_fields.append({field_description: value_}) From e3943dab8411edd8ba4c2f738ca3bd413c0c1fc8 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Tue, 18 Jul 2023 17:27:49 +0700 Subject: [PATCH 28/37] feature-8683: Add Options for Badges in Wizard --- app/api/badge_forms.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/api/badge_forms.py b/app/api/badge_forms.py index 08897999a0..e71c23396d 100644 --- a/app/api/badge_forms.py +++ b/app/api/badge_forms.py @@ -68,7 +68,8 @@ def after_get(badge_forms): class BadgeFormDetail(ResourceDetail): """BadgeForm Resource Detail""" - def before_get_object(self, view_kwargs): + @staticmethod + def before_get_object(view_kwargs): """ before get method :param view_kwargs: From 44c88f68b59d62229f77edb02c7dcdad347e8429 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Wed, 19 Jul 2023 09:46:59 +0700 Subject: [PATCH 29/37] feature-8683: Add Options for Badges in Wizard --- app/templates/pdf/badge_forms.html | 64 ++++++++++++++---------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/app/templates/pdf/badge_forms.html b/app/templates/pdf/badge_forms.html index 41b08b1549..9a4442f2c5 100644 --- a/app/templates/pdf/badge_forms.html +++ b/app/templates/pdf/badge_forms.html @@ -6,41 +6,37 @@ - +
-
-
- {% for badgeFieldForm in badgeFieldForms %} - {% if badgeFieldForm.custom_field == 'QR' %} -
- QR -
- {% else %} -

- {{ badgeFieldForm.sample_text }} -

- {% endif %} - {% endfor %} -
-
+ {% for badgeFieldForm in badgeFieldForms %} + {% if badgeFieldForm.custom_field == 'QR' %} +
+ QR +
+ {% else %} +

+ {{ badgeFieldForm.sample_text }} +

+ {% endif %} + {% endfor %}
\ No newline at end of file From 04ea004b71d152043975ecf7994b3088f55eb2ea Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Wed, 19 Jul 2023 20:14:44 +0700 Subject: [PATCH 30/37] feature-8683: Merge code development --- app/api/helpers/badge_forms.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py index 8e010d67e7..44fa966510 100644 --- a/app/api/helpers/badge_forms.py +++ b/app/api/helpers/badge_forms.py @@ -47,9 +47,9 @@ def get_value_from_field_indentifier(field: BadgeFieldForms, ticket_holder: Tick field.sample_text = getattr(ticket_holder, snake_case_field_identifier) or '' except AttributeError: try: - field.sample_text = ( - ticket_holder.complex_field_values[snake_case_field_identifier] or '' - ) + field.sample_text = ticket_holder.complex_field_values[ + snake_case_field_identifier + ] except AttributeError: print(f"get_value_from_field_indentifier ===={snake_case_field_identifier}") From 7f21dd8a27dd0fba6e0c9b37164143cbd575d1af Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Wed, 19 Jul 2023 20:47:20 +0700 Subject: [PATCH 31/37] feature-8683: Merge code development --- app/api/helpers/badge_forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py index 44fa966510..2e3d007fa0 100644 --- a/app/api/helpers/badge_forms.py +++ b/app/api/helpers/badge_forms.py @@ -44,7 +44,7 @@ def get_value_from_field_indentifier(field: BadgeFieldForms, ticket_holder: Tick """Get the value of a field.""" snake_case_field_identifier = to_snake_case(field.field_identifier) try: - field.sample_text = getattr(ticket_holder, snake_case_field_identifier) or '' + field.sample_text = getattr(ticket_holder, snake_case_field_identifier) except AttributeError: try: field.sample_text = ticket_holder.complex_field_values[ From a93712dce04da768d993eba89f880e9f9cf7dd99 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Wed, 19 Jul 2023 21:22:40 +0700 Subject: [PATCH 32/37] feature-8683: Merge code development --- app/api/helpers/badge_forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py index 2e3d007fa0..2b3061fdc8 100644 --- a/app/api/helpers/badge_forms.py +++ b/app/api/helpers/badge_forms.py @@ -51,7 +51,7 @@ def get_value_from_field_indentifier(field: BadgeFieldForms, ticket_holder: Tick snake_case_field_identifier ] except AttributeError: - print(f"get_value_from_field_indentifier ===={snake_case_field_identifier}") + print(snake_case_field_identifier) def get_value_from_qr_filed(field: BadgeFieldForms, ticket_holder: TicketHolder) -> dict: From 180a77c17620a091edacfb39889bddd207cb7bb3 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Wed, 19 Jul 2023 22:00:41 +0700 Subject: [PATCH 33/37] feature-8683: Merge code development --- app/api/helpers/badge_forms.py | 4 +-- docs/api/api_blueprint_source.apib | 4 ++- docs/api/blueprint/badge_forms.apib | 35 ++++++++++++++++++++++++++ docs/api/blueprint/ticket/tickets.apib | 34 +++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 docs/api/blueprint/badge_forms.apib diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py index 2b3061fdc8..fd24b97108 100644 --- a/app/api/helpers/badge_forms.py +++ b/app/api/helpers/badge_forms.py @@ -47,9 +47,7 @@ def get_value_from_field_indentifier(field: BadgeFieldForms, ticket_holder: Tick field.sample_text = getattr(ticket_holder, snake_case_field_identifier) except AttributeError: try: - field.sample_text = ticket_holder.complex_field_values[ - snake_case_field_identifier - ] + field.sample_text = ticket_holder.complex_field_values[field.field_identifier] except AttributeError: print(snake_case_field_identifier) diff --git a/docs/api/api_blueprint_source.apib b/docs/api/api_blueprint_source.apib index de001c5dc8..3d8465ddd6 100644 --- a/docs/api/api_blueprint_source.apib +++ b/docs/api/api_blueprint_source.apib @@ -131,4 +131,6 @@ The Open Event API Server - \ No newline at end of file + + + \ No newline at end of file diff --git a/docs/api/blueprint/badge_forms.apib b/docs/api/blueprint/badge_forms.apib new file mode 100644 index 0000000000..97b1957148 --- /dev/null +++ b/docs/api/blueprint/badge_forms.apib @@ -0,0 +1,35 @@ +# Group Badge Forms +Badge Forms related to the events. + +| Parameter | Description | Type | Required | +|:----------|-------------|------|----------| +| `badge-color` | Badge Color | string | - | +| `badge-size` | Badge Size | string | - | +| `badge-id` | Badge Id | string | **yes** | +| `badge-image-url` | Badge Image Url | String | - | +| `badge-orientation` | Badge Orientation | String | - | + + + +## Print PDF for an Attendee [/v1/badge-forms/print-badge-pdf] + +### Print PDF for an Attendee [POST] + ++ Request + + + Headers + + Accept: application/vnd.api+json + + Authorization: JWT + + + Body + + { + "attendee_id": 5, + "list_field_show" : ["email", "jobTitle"] + } + ++ Response 200 (application/pdf) + + File PDF diff --git a/docs/api/blueprint/ticket/tickets.apib b/docs/api/blueprint/ticket/tickets.apib index 37ab9e8398..beaccf70c4 100644 --- a/docs/api/blueprint/ticket/tickets.apib +++ b/docs/api/blueprint/ticket/tickets.apib @@ -759,3 +759,37 @@ Delete a single ticket. "self": "/v1/orders/7201904e-c695-4251-a30a-61765a37ff24/tickets" } } + +## List Badge Forms for an Ticket [/v1/tickets/{ticket_id}/badge-forms] ++ Parameters + + ticket_id: 1 (integer) - id of the ticket + +### List Badge Forms for an Ticket [GET] + ++ Request + + + Headers + + Accept: application/vnd.api+json + + Authorization: JWT + ++ Response 200 (application/vnd.api+json) + + [ + { + "custom_field": "Email", + "field_identifier": "email", + "id": 8200 + }, + { + "custom_field": "Are you fluent in any other of the following languages?", + "field_identifier": "fluent_language", + "id": 8202 + }, + { + "custom_field": "Age Group", + "field_identifier": "ageGroup", + "id": 8201 + } + ] From 938382b09ec9cb06df0637bb33ba3fd1fa5fdb84 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Wed, 19 Jul 2023 23:03:06 +0700 Subject: [PATCH 34/37] feature-8683: Merge code development --- docs/api/blueprint/ticket/tickets.apib | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/blueprint/ticket/tickets.apib b/docs/api/blueprint/ticket/tickets.apib index beaccf70c4..ddda570adf 100644 --- a/docs/api/blueprint/ticket/tickets.apib +++ b/docs/api/blueprint/ticket/tickets.apib @@ -762,7 +762,7 @@ Delete a single ticket. ## List Badge Forms for an Ticket [/v1/tickets/{ticket_id}/badge-forms] + Parameters - + ticket_id: 1 (integer) - id of the ticket + + ticket_id: 1 (integer) - ID of the ticket in the form of an integer ### List Badge Forms for an Ticket [GET] @@ -774,7 +774,7 @@ Delete a single ticket. Authorization: JWT -+ Response 200 (application/vnd.api+json) ++ Response 200 (application/json) [ { From c3864fa907a97b6f78677b2c667bdf30bb15b572 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Thu, 20 Jul 2023 08:51:09 +0700 Subject: [PATCH 35/37] feature-8683: Merge code development --- docs/api/blueprint/badge_forms.apib | 25 ------------------- docs/api/blueprint/ticket/tickets.apib | 34 -------------------------- 2 files changed, 59 deletions(-) diff --git a/docs/api/blueprint/badge_forms.apib b/docs/api/blueprint/badge_forms.apib index 97b1957148..1386f4b90d 100644 --- a/docs/api/blueprint/badge_forms.apib +++ b/docs/api/blueprint/badge_forms.apib @@ -8,28 +8,3 @@ Badge Forms related to the events. | `badge-id` | Badge Id | string | **yes** | | `badge-image-url` | Badge Image Url | String | - | | `badge-orientation` | Badge Orientation | String | - | - - - -## Print PDF for an Attendee [/v1/badge-forms/print-badge-pdf] - -### Print PDF for an Attendee [POST] - -+ Request - - + Headers - - Accept: application/vnd.api+json - - Authorization: JWT - - + Body - - { - "attendee_id": 5, - "list_field_show" : ["email", "jobTitle"] - } - -+ Response 200 (application/pdf) - - File PDF diff --git a/docs/api/blueprint/ticket/tickets.apib b/docs/api/blueprint/ticket/tickets.apib index ddda570adf..37ab9e8398 100644 --- a/docs/api/blueprint/ticket/tickets.apib +++ b/docs/api/blueprint/ticket/tickets.apib @@ -759,37 +759,3 @@ Delete a single ticket. "self": "/v1/orders/7201904e-c695-4251-a30a-61765a37ff24/tickets" } } - -## List Badge Forms for an Ticket [/v1/tickets/{ticket_id}/badge-forms] -+ Parameters - + ticket_id: 1 (integer) - ID of the ticket in the form of an integer - -### List Badge Forms for an Ticket [GET] - -+ Request - - + Headers - - Accept: application/vnd.api+json - - Authorization: JWT - -+ Response 200 (application/json) - - [ - { - "custom_field": "Email", - "field_identifier": "email", - "id": 8200 - }, - { - "custom_field": "Are you fluent in any other of the following languages?", - "field_identifier": "fluent_language", - "id": 8202 - }, - { - "custom_field": "Age Group", - "field_identifier": "ageGroup", - "id": 8201 - } - ] From addc6d17bae83f09548ed21717caad2517b17337 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Thu, 20 Jul 2023 10:11:58 +0700 Subject: [PATCH 36/37] feature-8683: Add Options for Badges in Wizard --- app/api/custom/badge_forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/custom/badge_forms.py b/app/api/custom/badge_forms.py index 4af5b7e3a6..cd5e1de2df 100644 --- a/app/api/custom/badge_forms.py +++ b/app/api/custom/badge_forms.py @@ -13,7 +13,7 @@ ) -@badge_forms_routes.route('/preivew-badge-pdf', methods=['POST']) +@badge_forms_routes.route('/preview-badge-pdf', methods=['POST']) @jwt_required def preivew_badge_pdf(): """Preview Badge Template PDF""" From 3f03fe3110c3ba804019518b3f0342de6b8ff999 Mon Sep 17 00:00:00 2001 From: lthanhhieu Date: Thu, 20 Jul 2023 11:46:37 +0700 Subject: [PATCH 37/37] feature-8683: EVENTYAY ID in CVF should be the id of ticket holder. --- app/api/helpers/badge_forms.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/api/helpers/badge_forms.py b/app/api/helpers/badge_forms.py index fd24b97108..cdb3c359a3 100644 --- a/app/api/helpers/badge_forms.py +++ b/app/api/helpers/badge_forms.py @@ -75,9 +75,7 @@ def get_value_from_qr_filed(field: BadgeFieldForms, ticket_holder: TicketHolder) print(field_identifier) qr_value.update({field_identifier: str(value_)}) - qr_value.update( - {'custom_fields': custom_fields, 'ticket_id': ticket_holder.ticket_id} - ) + qr_value.update({'custom_fields': custom_fields, 'ticket_id': ticket_holder.id}) return qr_value