def resend_emails(): """ Sends confirmation email for pending and completed orders on organizer request :param order_identifier: :return: JSON response if the email was succesfully sent """ order_identifier = request.json['data']['order'] order = safe_query(db, Order, 'identifier', order_identifier, 'identifier') if (has_access('is_coorganizer', event_id=order.event_id)): if order.status == 'completed' or order.status == 'placed': # fetch tickets attachment order_identifier = order.identifier key = UPLOAD_PATHS['pdf']['tickets_all'].format(identifier=order_identifier) ticket_path = 'generated/tickets/{}/{}/'.format(key, generate_hash(key)) + order_identifier + '.pdf' key = UPLOAD_PATHS['pdf']['order'].format(identifier=order_identifier) invoice_path = 'generated/invoices/{}/{}/'.format(key, generate_hash(key)) + order_identifier + '.pdf' # send email. send_email_to_attendees(order=order, purchaser_id=current_user.id, attachments=[ticket_path, invoice_path]) return jsonify(status=True, message="Verification emails for order : {} has been sent succesfully". format(order_identifier)) else: return UnprocessableEntityError({'source': 'data/order'}, "Only placed and completed orders have confirmation").respond() else: return ForbiddenError({'source': ''}, "Co-Organizer Access Required").respond()
def after_update_object(self, order, data, view_kwargs): """ :param order: :param data: :param view_kwargs: :return: """ # create pdf tickets. create_pdf_tickets_for_holder(order) if order.status == 'cancelled' and order.deleted_at is None: send_order_cancel_email(order) send_notif_ticket_cancel(order) # delete the attendees so that the tickets are unlocked. delete_related_attendees_for_order(order) elif (order.status == 'completed' or order.status == 'placed') and order.deleted_at is None: # Send email to attendees with invoices and tickets attached order_identifier = order.identifier key = UPLOAD_PATHS['pdf']['ticket_attendee'].format( identifier=order_identifier) ticket_path = 'generated/tickets/{}/{}/'.format( key, generate_hash(key)) + order_identifier + '.pdf' key = UPLOAD_PATHS['pdf']['order'].format( identifier=order_identifier) invoice_path = 'generated/invoices/{}/{}/'.format( key, generate_hash(key)) + order_identifier + '.pdf' # send email and notifications. send_email_to_attendees(order=order, purchaser_id=current_user.id, attachments=[ticket_path, invoice_path]) send_notif_to_attendees(order, current_user.id) if order.payment_mode in ['free', 'bank', 'cheque', 'onsite']: order.completed_at = datetime.utcnow() order_url = make_frontend_url(path='/orders/{identifier}'.format( identifier=order.identifier)) for organizer in order.event.organizers: send_notif_ticket_purchase_organizer(organizer, order.invoice_number, order_url, order.event.name, order.identifier) if order.event.owner: send_notif_ticket_purchase_organizer(order.event.owner, order.invoice_number, order_url, order.event.name, order.identifier)
def test_generate_hash(self): """Test generation of hash for a key.""" secret_key = 'secret_key' test_input = 'case1' exepected_output = 'WUFCV0xHVk' actual_output = generate_hash(test_input, secret_key) self.assertEqual(exepected_output, actual_output) self.assertEqual(len(actual_output), 10) test_input = '/static/uploads/pdf/temp/' exepected_output = 'MzRueVhjY0' actual_output = generate_hash(test_input, secret_key) self.assertEqual(exepected_output, actual_output) self.assertEqual(len(actual_output), 10)
def order_invoices(order_identifier): if current_user: try: order = Order.query.filter_by(identifier=order_identifier).first() except NoResultFound: return NotFoundError({ 'source': '' }, 'Order Invoice not found').respond() if current_user.can_download_tickets(order): key = UPLOAD_PATHS['pdf']['order'].format( identifier=order_identifier) file_path = ('../generated/invoices/{}/{}/'.format( key, generate_hash(key)) + order_identifier + '.pdf') try: return return_file('invoice', file_path, order_identifier) except FileNotFoundError: create_pdf_tickets_for_holder(order) return return_file('invoice', file_path, order_identifier) else: return ForbiddenError({ 'source': '' }, 'Unauthorized Access').respond() else: return ForbiddenError({ 'source': '' }, 'Authentication Required to access Invoice').respond()
def ticket_attendee_authorized(order_identifier): if current_user: try: order = Order.query.filter_by(identifier=order_identifier).first() except NoResultFound: raise NotFoundError({'source': ''}, 'This ticket is not associated with any order') if (has_access( 'is_coorganizer_or_user_itself', event_id=order.event_id, user_id=order.user_id, ) or order.is_attendee(current_user)): key = UPLOAD_PATHS['pdf']['tickets_all'].format( identifier=order_identifier) file_path = ( '../generated/tickets/{}/{}/'.format(key, generate_hash(key)) + order_identifier + '.pdf') try: return return_file('ticket', file_path, order_identifier) except FileNotFoundError: create_pdf_tickets_for_holder(order) return return_file('ticket', file_path, order_identifier) else: raise ForbiddenError({'source': ''}, 'Unauthorized Access') else: raise ForbiddenError({'source': ''}, 'Authentication Required to access ticket')
def event_invoices(invoice_identifier): if not current_user: raise ForbiddenError({'source': ''}, 'Authentication Required to access Invoice') try: event_invoice = EventInvoice.query.filter_by( identifier=invoice_identifier).first() event_id = event_invoice.event_id except NoResultFound: raise NotFoundError({'source': ''}, 'Event Invoice not found') if not current_user.is_organizer(event_id) and not current_user.is_staff: raise ForbiddenError({'source': ''}, 'Unauthorized Access') key = UPLOAD_PATHS['pdf']['event_invoices'].format( identifier=invoice_identifier) file_path = ( '../generated/invoices/{}/{}/'.format(key, generate_hash(key)) + invoice_identifier + '.pdf') try: return return_file('event-invoice', file_path, invoice_identifier) except FileNotFoundError: raise ObjectNotFound( {'source': ''}, "The Event Invoice isn't available at the moment. \ Invoices are usually issued on the 1st of every month", )
def ticket_attendee_authorized(order_identifier): if current_user: try: order = Order.query.filter_by(identifier=order_identifier).first() except NoResultFound: return NotFoundError({ 'source': '' }, 'This ticket is not associated with any order').respond() if current_user.can_download_tickets(order): key = UPLOAD_PATHS['pdf']['tickets_all'].format( identifier=order_identifier) file_path = ( '../generated/tickets/{}/{}/'.format(key, generate_hash(key)) + order_identifier + '.pdf') try: return return_file('ticket', file_path, order_identifier) except FileNotFoundError: create_pdf_tickets_for_holder(order) return return_file('ticket', file_path, order_identifier) else: return ForbiddenError({ 'source': '' }, 'Unauthorized Access').respond() else: return ForbiddenError({ 'source': '' }, 'Authentication Required to access ticket').respond()
def pdf_url_path(self) -> str: key = UPLOAD_PATHS['pdf']['tickets_all'].format( identifier=self.order.identifier, extra_identifier=self.id ) return ( 'generated/tickets/{}/{}/'.format(key, generate_hash(key)) + self.order.identifier + '.pdf' )
def create_save_resized_image(image_file, basewidth=None, maintain_aspect=None, height_size=None, upload_path=None, ext='jpg', remove_after_upload=False, resize=True): """ Create and Save the resized version of the background image :param resize: :param upload_path: :param ext: :param remove_after_upload: :param height_size: :param maintain_aspect: :param basewidth: :param image_file: :return: """ if not image_file: return None filename = '{filename}.{ext}'.format(filename=get_file_name(), ext=ext) data = urllib.request.urlopen(image_file).read() image_file = io.BytesIO(data) try: im = Image.open(image_file) except IOError: raise IOError("Corrupt/Invalid Image") # Convert to jpeg for lower file size. if im.format != 'JPEG': img = im.convert('RGB') else: img = im if resize: if maintain_aspect: width_percent = (basewidth / float(img.size[0])) height_size = int((float(img.size[1]) * float(width_percent))) img = img.resize((basewidth, height_size), PIL.Image.ANTIALIAS) temp_file_relative_path = 'static/media/temp/' + generate_hash(str(image_file)) + get_file_name() + '.jpg' temp_file_path = app.config['BASE_DIR'] + '/' + temp_file_relative_path dir_path = temp_file_path.rsplit('/', 1)[0] # create dirs if not present if not os.path.isdir(dir_path): os.makedirs(dir_path) img.save(temp_file_path) upfile = UploadedFile(file_path=temp_file_path, filename=filename) if remove_after_upload: # os.remove(image_file) No point in removing in memory file pass uploaded_url = upload(upfile, upload_path) os.remove(temp_file_path) return uploaded_url
def create_save_resized_image(image_file, basewidth=None, maintain_aspect=None, height_size=None, upload_path=None, ext='jpg', remove_after_upload=False, resize=True): """ Create and Save the resized version of the background image :param resize: :param upload_path: :param ext: :param remove_after_upload: :param height_size: :param maintain_aspect: :param basewidth: :param image_file: :return: """ if not image_file: return None filename = '{filename}.{ext}'.format(filename=get_file_name(), ext=ext) data = urllib.request.urlopen(image_file).read() image_file = io.BytesIO(data) try: im = Image.open(image_file) except IOError: raise IOError("Corrupt/Invalid Image") # Convert to jpeg for lower file size. if im.format is not 'JPEG': img = im.convert('RGB') else: img = im if resize: if maintain_aspect: width_percent = (basewidth / float(img.size[0])) height_size = int((float(img.size[1]) * float(width_percent))) img = img.resize((basewidth, height_size), PIL.Image.ANTIALIAS) temp_file_relative_path = 'static/media/temp/' + generate_hash(str(image_file)) + get_file_name() + '.jpg' temp_file_path = app.config['BASE_DIR'] + '/' + temp_file_relative_path dir_path = temp_file_path.rsplit('/', 1)[0] # create dirs if not present if not os.path.isdir(dir_path): os.makedirs(dir_path) img.save(temp_file_path) upfile = UploadedFile(file_path=temp_file_path, filename=filename) if remove_after_upload: # os.remove(image_file) No point in removing in memory file pass uploaded_url = upload(upfile, upload_path) os.remove(temp_file_path) return uploaded_url
def on_order_completed(order): # send e-mail and notifications if the order status is completed if not (order.status == 'completed' or order.status == 'placed'): return # fetch tickets attachment order_identifier = order.identifier key = UPLOAD_PATHS['pdf']['tickets_all'].format( identifier=order_identifier) ticket_path = ('generated/tickets/{}/{}/'.format(key, generate_hash(key)) + order_identifier + '.pdf') key = UPLOAD_PATHS['pdf']['order'].format(identifier=order_identifier) invoice_path = ( 'generated/invoices/{}/{}/'.format(key, generate_hash(key)) + order_identifier + '.pdf') # send email and notifications. send_email_to_attendees( order=order, purchaser_id=current_user.id, attachments=[ticket_path, invoice_path], ) send_notif_to_attendees(order, current_user.id) if order.payment_mode in ['free', 'bank', 'cheque', 'onsite']: order.completed_at = datetime.utcnow() order_url = make_frontend_url(path='/orders/{identifier}'.format( identifier=order.identifier)) for organizer in set(order.event.organizers + order.event.coorganizers + [order.event.owner]): if not organizer: continue send_notif_ticket_purchase_organizer( organizer, order.invoice_number, order_url, order.event.name, order.identifier, )
def create_system_image(image_file=None, upload_path=None, unique_identifier=None, ext='jpg'): """ Create System Images for Event Topics :param upload_path: :param ext: :param remove_after_upload: :param image_file: :return: """ # Get an unique identifier from uuid if not provided filename = '{filename}.{ext}'.format(filename=get_file_name(), ext=ext) if image_file: with urllib.request.urlopen(image_file) as img_data: image_file = io.BytesIO(img_data.read()) else: file_relative_path = 'static/default_system_image.png' image_file = current_app.config['BASE_DIR'] + '/' + file_relative_path try: im = Image.open(image_file) except IOError: raise IOError("Corrupt/Invalid Image") # Convert to jpeg for lower file size. if im.format != 'JPEG': img = im.convert('RGB') else: img = im temp_file_relative_path = ('static/media/temp/' + generate_hash(str(image_file)) + get_file_name() + '.jpg') temp_file_path = current_app.config[ 'BASE_DIR'] + '/' + temp_file_relative_path dir_path = temp_file_path.rsplit('/', 1)[0] # create dirs if not present if not os.path.isdir(dir_path): os.makedirs(dir_path) img.save(temp_file_path) upfile = UploadedFile(file_path=temp_file_path, filename=filename) if not upload_path: upload_path = UPLOAD_PATHS['event_topic']['system_image'].format( event_topic_id=unique_identifier) uploaded_url = upload(upfile, upload_path) os.remove(temp_file_path) image = {'system_image_url': uploaded_url} return image
def create_system_image(image_file=None, upload_path=None, unique_identifier=None, ext='jpg'): """ Create System Images for Event Topics :param upload_path: :param ext: :param remove_after_upload: :param image_file: :return: """ # Get an unique identifier from uuid if not provided filename = '{filename}.{ext}'.format(filename=get_file_name(), ext=ext) if image_file: with urllib.request.urlopen(image_file) as img_data: image_file = io.BytesIO(img_data.read()) else: file_relative_path = 'static/default_system_image.png' image_file = app.config['BASE_DIR'] + '/' + file_relative_path try: im = Image.open(image_file) except IOError: raise IOError("Corrupt/Invalid Image") # Convert to jpeg for lower file size. if im.format is not 'JPEG': img = im.convert('RGB') else: img = im temp_file_relative_path = 'static/media/temp/' + generate_hash(str(image_file)) + get_file_name() + '.jpg' temp_file_path = app.config['BASE_DIR'] + '/' + temp_file_relative_path dir_path = temp_file_path.rsplit('/', 1)[0] # create dirs if not present if not os.path.isdir(dir_path): os.makedirs(dir_path) img.save(temp_file_path) upfile = UploadedFile(file_path=temp_file_path, filename=filename) if not upload_path: upload_path = UPLOAD_PATHS['event_topic']['system_image'].format(event_topic_id=unique_identifier) uploaded_url = upload(upfile, upload_path) os.remove(temp_file_path) image = {'system_image_url': uploaded_url} return image
def order_invoices(order_identifier): if current_user: try: order = Order.query.filter_by(identifier=order_identifier).first() user_id = order.user.id except NoResultFound: return NotFoundError({'source': ''}, 'Order Invoice not found').respond() if current_user.id == user_id: key = UPLOAD_PATHS['pdf']['order'].format(identifier=order_identifier) file_path = '../generated/invoices/{}/{}/'.format(key, generate_hash(key)) + order_identifier + '.pdf' response = make_response(send_file(file_path)) response.headers['Content-Disposition'] = 'attachment; filename=invoice-%s.zip' % order_identifier return response else: return ForbiddenError({'source': ''}, 'Unauthorized Access').respond() else: return ForbiddenError({'source': ''}, 'Authentication Required to access Invoice').respond()
def ticket_attendee_authorized(order_identifier): if current_user: try: order = Order.query.filter_by(identifier=order_identifier).first() user_id = order.user.id except NoResultFound: return NotFoundError({'source': ''}, 'This ticket is not associated with any order').respond() if current_user.id == user_id: key = UPLOAD_PATHS['pdf']['ticket_attendee'].format(identifier=order_identifier) file_path = '../generated/tickets/{}/{}/'.format(key, generate_hash(key)) + order_identifier + '.pdf' try: response = make_response(send_file(file_path)) response.headers['Content-Disposition'] = 'attachment; filename=ticket-%s.zip' % order_identifier return response except FileNotFoundError: create_pdf_tickets_for_holder(order) return redirect(url_for('ticket_blueprint.ticket_attendee_authorized', order_identifier=order_identifier)) else: return ForbiddenError({'source': ''}, 'Unauthorized Access').respond() else: return ForbiddenError({'source': ''}, 'Authentication Required to access ticket').respond()
def invoice_pdf_path(self) -> str: key = UPLOAD_PATHS['pdf']['order'].format(identifier=self.identifier) return ('generated/invoices/{}/{}/'.format(key, generate_hash(key)) + self.identifier + '.pdf')
def complete_order(order_id): data = request.get_json() for attribute in data: data[attribute.replace('-', '_')] = data.pop(attribute) order = Order.query.filter_by(id=order_id).first() order_schema = OrderSchema() if (not has_access('is_coorganizer', event_id=order.event_id)) and ( not current_user.id == order.user_id): return make_response( jsonify(status='Access Forbidden', error='You cannot update an order.'), 403) if has_access('is_coorganizer', event_id=order.event_id) and 'status' in data: if data['status'] != 'cancelled': return make_response( jsonify(status='Access Forbidden', error='You can only cancel an order.'), 403, ) elif data['status'] == 'cancelled': order.status = 'cancelled' db.session.add(order) attendees = (db.session.query(TicketHolder).filter_by( order_id=order_id, deleted_at=None).all()) for attendee in attendees: attendee.deleted_at = datetime.now(pytz.utc) db.session.add(attendee) db.session.commit() send_order_cancel_email(order) send_notif_ticket_cancel(order) return order_schema.dump(order) updated_attendees = data['attendees'] for updated_attendee in updated_attendees: for attribute in updated_attendee: updated_attendee[attribute.replace( '-', '_')] = updated_attendee.pop(attribute) if get_count(db.session.query(TicketHolder).filter_by( order_id=order_id)) != len(updated_attendees): return make_response( jsonify( status='Unprocessable Entity', error='You need to provide info of all attendees.', ), 422, ) else: attendees = (db.session.query(TicketHolder).filter_by( order_id=order_id, deleted_at=None).all()) form_fields = (db.session.query(CustomForms).filter_by( event_id=order.event_id, form='attendee', is_included=True).all()) for attendee, updated_attendee in zip(attendees, updated_attendees): for field in form_fields: if (field.is_required is True and field.field_identifier not in updated_attendee): return make_response( jsonify( status='Unprocessable Entity', error='{} is a required field.'.format( field.field_identifier), ), 422, ) if field.field_identifier in updated_attendee: setattr( attendee, field.field_identifier, updated_attendee[field.field_identifier], ) db.session.add(attendee) # modified_at not getting filled if order.amount == 0: order.status = 'completed' order.completed_at = datetime.utcnow() elif order.amount > 0: if 'payment_mode' not in data: return make_response( jsonify(status='Unprocessable Entity', error='Payment mode not specified.'), 422, ) if data['payment_mode'] in ['bank', 'cheque', 'onsite']: order.status = 'placed' order.completed_at = datetime.utcnow() else: order.status = 'pending' if 'is_billing_enabled' in data: if data['is_billing_enabled']: if (('company' not in data) or ('address' not in data) or ('city' not in data) or ('zipcode' not in data) or ('country' not in data)): return make_response( jsonify( status='Unprocessable Entity', error='Billing information incomplete.', ), 422, ) else: return make_response( jsonify( status='Unprocessable Entity', error='Billing information incomplete.', ), 422, ) else: return make_response( jsonify( status='Unprocessable Entity', error='Billing information is mandatory ' 'for this order.', ), 422, ) order.company = data['company'] order.address = data['address'] order.city = data['city'] order.zipcode = data['zipcode'] order.country = data['country'] order.payment_mode = data['payment_mode'] if 'state' in data: order.state = data['state'] if 'tax_business_info' in data: order.tax_business_info = data['tax_business_info'] db.session.add(order) db.session.commit() create_pdf_tickets_for_holder(order) if (order.status == 'completed' or order.status == 'placed') and (order.deleted_at is None): order_identifier = order.identifier key = UPLOAD_PATHS['pdf']['tickets_all'].format( identifier=order_identifier) ticket_path = ( 'generated/tickets/{}/{}/'.format(key, generate_hash(key)) + order_identifier + '.pdf') key = UPLOAD_PATHS['pdf']['order'].format(identifier=order_identifier) invoice_path = ( 'generated/invoices/{}/{}/'.format(key, generate_hash(key)) + order_identifier + '.pdf') # send email and notifications. send_email_to_attendees( order=order, purchaser_id=current_user.id, attachments=[ticket_path, invoice_path], ) send_notif_to_attendees(order, current_user.id) order_url = make_frontend_url(path='/orders/{identifier}'.format( identifier=order.identifier)) for organizer in order.event.organizers: send_notif_ticket_purchase_organizer( organizer, order.invoice_number, order_url, order.event.name, order.identifier, ) if order.event.owner: send_notif_ticket_purchase_organizer( order.event.owner, order.invoice_number, order_url, order.event.name, order.identifier, ) return order_schema.dump(order)
def after_create_object(self, order, data, view_kwargs): """ after create object method for OrderListPost Class :param order: Object created from mashmallow_jsonapi :param data: :param view_kwargs: :return: """ order_tickets = {} for holder in order.ticket_holders: save_to_db(holder) if not order_tickets.get(holder.ticket_id): order_tickets[holder.ticket_id] = 1 else: order_tickets[holder.ticket_id] += 1 order.user = current_user # create pdf tickets. create_pdf_tickets_for_holder(order) for ticket in order_tickets: od = OrderTicket(order_id=order.id, ticket_id=ticket, quantity=order_tickets[ticket]) save_to_db(od) order.quantity = order.tickets_count save_to_db(order) # if not has_access('is_coorganizer', event_id=data['event']): # TicketingManager.calculate_update_amount(order) # send e-mail and notifications if the order status is completed if order.status == 'completed' or order.status == 'placed': # fetch tickets attachment order_identifier = order.identifier key = UPLOAD_PATHS['pdf']['ticket_attendee'].format( identifier=order_identifier) ticket_path = 'generated/tickets/{}/{}/'.format( key, generate_hash(key)) + order_identifier + '.pdf' key = UPLOAD_PATHS['pdf']['order'].format( identifier=order_identifier) invoice_path = 'generated/invoices/{}/{}/'.format( key, generate_hash(key)) + order_identifier + '.pdf' # send email and notifications. send_email_to_attendees(order=order, purchaser_id=current_user.id, attachments=[ticket_path, invoice_path]) send_notif_to_attendees(order, current_user.id) if order.payment_mode in ['free', 'bank', 'cheque', 'onsite']: order.completed_at = datetime.utcnow() order_url = make_frontend_url(path='/orders/{identifier}'.format( identifier=order.identifier)) for organizer in order.event.organizers: send_notif_ticket_purchase_organizer(organizer, order.invoice_number, order_url, order.event.name, order.identifier) data['user_id'] = current_user.id