from flask import session, jsonify from app.api.schemas.user_update import UserUpdateSchema # from app.models.loan import Loan from app.utils.logger import logger from app.api.services.base_service import BaseService # from app.api.schemas.eligibility_check import EligibilityCheckSchema from marshmallow import ValidationError from app.api.enums import TransactionType # from app.api.integrations import SimbrellaIntegration from app.extensions import db from app.models import Members, MembersActions, MembersProfile, Payments, MembersProducts, ProvisionActions # from app.api.services.offer_analysis import OfferAnalysis from app.api.helpers.response_helper import ResponseHelper from werkzeug.security import generate_password_hash, check_password_hash from app.api.schemas.user import UserSchema from app.api.schemas.start_profile import StartProfileSchema from app.api.schemas.profile_links import ProfileLinksSchema from flask_mail import Mail, Message import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from sendgrid import SendGridAPIClient from sendgrid.helpers.mail import Mail import datetime import jwt import random from app.config import Config import smtplib, ssl from email.message import EmailMessage from app.notifications.aws.aws_mailer import send_email_ses class AccountService(BaseService): JWT_SECRET_KEY = Config.JWT_SECRET_KEY SEND_EMAIL_FROM = Config.SEND_EMAIL_FROM SEND_EMAIL_PASS = Config.SEND_EMAIL_PASS THIS_SITE_URL = Config.THIS_SITE_URL @staticmethod def process_bar_request(data): bar_data = { "last_update": datetime.datetime.utcnow(), "top_bar": [ {"id": "1", "description": "Contacts", "last_update": "10-10-2010 11:00 AM", "value": random.randint(0, 10), "data_span": 'Last 2 months', "link": "#", "extra_style": ''}, {"id": "2", "description": "Site Traffic", "last_update": "10-10-2010 11:30 AM", "value": random.randint(0, 10), "data_span": 'Past 12 hours', "link": "#", "extra_style": ''}, {"id": "3", "description": "Appointments", "last_update": "10-12-2010 11:30 AM", "value": random.randint(0, 10), "data_span": 'Last 14 days', "link": "#", "extra_style": ''}, {"id": "4", "description": "Upgrade Account", "last_update": "10-12-2010 11:30 AM", "value": "Free Trial", "data_span": 'End: 10/10/2025', "link": "/subscription", "extra_style": " billing "} ] } return ResponseHelper.success(data=bar_data) @staticmethod def process_bar_data(data): try: with db.session.begin(): validated_data = AccountService.validate_data(data, UserSchema()) user_token = validated_data.get('token') uid = str(validated_data.get('uid')) member_data = Members.get_member_by_uid(uid) option_name = member_data.option_name # "Free Trial" if option_name is not None and option_name != "": next_bill = f"Bill: {member_data.next_billing}" view_sub = "Account" bill_style = " next_billing " else: option_name = "Free Trial" next_bill = f"Ends: {member_data.trial_end}" view_sub = "Upgrade Account" bill_style = " billing " contacts_count = 0 # random.randint(0, 10) appointments_count = 0 site_traffic_count = 0 bar_data = { "last_update": datetime.datetime.utcnow(), "top_bar": [ {"id": "1", "description": "Contacts", "last_update": "10-10-2010 11:00 AM", "value": contacts_count, "data_span": 'Last 2 months', "link": "/contacts", "extra_style": ''}, {"id": "2", "description": "Appointments", "last_update": "10-12-2010 11:30 AM", "value": appointments_count, "data_span": 'Last 14 days', "link": "/appointments", "extra_style": ''}, {"id": "3", "description": "Site Traffic", "last_update": "10-10-2010 11:30 AM", "value": site_traffic_count, "data_span": 'Past 12 hours', "link": "/traffic", "extra_style": ''}, {"id": "4", "description": view_sub, "last_update": "10-12-2010 11:30 AM", "value": option_name, "data_span": next_bill, "link": "/subscription", "extra_style": bill_style} ] } return ResponseHelper.success(data=bar_data) except ValidationError as err: logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.unprocessable_entity(result_description="Validation exception") except ValueError as err: logger.error(f"{getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.error(result_description=str(err)) except Exception as e: logger.error(f"An error occurred: {str(e)}", exc_info=True) db.session.rollback() return ResponseHelper.internal_server_error() def process_action_request(data): try: with db.session.begin(): validated_data = AccountService.validate_data(data, UserSchema()) user_token = validated_data.get('token') uid = str(validated_data.get('uid')) member_data = Members.get_member_by_uid(uid) member_actions = MembersActions.get_recent_member_actions(member_data.id) member_actions_data = [] if member_actions: for t in member_actions: member_actions_data.append({ 'id': t.id, 'uid': t.uid, 'member_id': t.member_id, 'member_uid': t.member_uid, 'action_label': t.action_label, 'action_name': t.action_name, 'status_description': t.status_description, 'status': t.status, 'added': t.added, 'updated': t.updated }) action_data = { "recent_actions": member_actions_data, "last_update": datetime.datetime.utcnow(), "initial": random.randint(0, 10), "processing": random.randint(0, 10), "verifying": random.randint(0, 10), "completed": random.randint(0, 10) } # logger.info(f"Member Actions : {action_data}") return ResponseHelper.success(data=action_data) except ValidationError as err: logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.unprocessable_entity(result_description="Validation exception") except ValueError as err: logger.error(f"{getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.error(result_description=str(err)) except Exception as e: logger.error(f"An error occurred: {str(e)}", exc_info=True) db.session.rollback() return ResponseHelper.internal_server_error() @staticmethod def process_request(data): try: with db.session.begin(): validated_data = AccountService.validate_data(data, UserSchema()) user_token = validated_data.get('token') uid = str(validated_data.get('uid')) member = Members.get_member_by_uid(uid) # Simulate processing response_data = { "member_id": member.id, "uid": str(uid), "username": member.username, "account_name": member.account_name, "profile_completed": member.profile_completed, "firstname": member.firstname, "lastname": member.lastname, "email": member.email, "room": member.uid, "picture": 'https://media.mermsemr.com/media/show/merms-profile', "token": user_token } return ResponseHelper.success(data=response_data) except ValidationError as err: logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.unprocessable_entity(result_description="Validation exception") except ValueError as err: logger.error(f"{getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.error(result_description=str(err)) except Exception as e: logger.error(f"An error occurred: {str(e)}", exc_info=True) db.session.rollback() return ResponseHelper.internal_server_error() @staticmethod def process_startprofile(data): try: with db.session.begin(): validated_data = AccountService.validate_data(data, StartProfileSchema()) user_token = validated_data.get('token') uid = str(validated_data.get('uid')) practice = str(validated_data.get('practice')) specialization = str(validated_data.get('specialization')) introduction = str(validated_data.get('introduction')) url_name = str(validated_data.get('url_name')) # verify is anybody is using this url name urlNammeData = MembersProfile.get_any_member_profile_by_url_name(url_name) if urlNammeData: return { "error": 'Duplicate url name', "error_message": 'Try another url name', "url_name": url_name, }, 400 profile_uid = '' profile_completed = None member = Members.get_member_by_uid(uid) if member: # Simulate processing member_data = { "member_id": member.id, "uid": str(uid), "username": member.username, "account_name": member.account_name, "firstname": member.firstname, "lastname": member.lastname, "email": member.email, "room": member.uid, "token": user_token } current_profile = MembersProfile.get_member_profile_by_member_id(member.id) if current_profile is not None: profile_uid = current_profile.uid profile_completed = member.profile_completed else: profile_result = MembersProfile.create_member_profile(member.id, practice, specialization, introduction, url_name) if profile_result: profile_uid = profile_result.uid current_profile = MembersProfile.get_member_profile_by_member_id(member.id) if profile_uid is not None and profile_uid != '' and current_profile is not None: profile_completed = Members.set_member_profile_completed(member_data['uid']) result_data = { "profile_completed": profile_completed, "profile_uid": profile_uid, "last_update": datetime.datetime.utcnow() } return ResponseHelper.success(data=result_data) except ValidationError as err: logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.unprocessable_entity(result_description="Validation exception") except ValueError as err: logger.error(f"{getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.error(result_description=str(err)) except Exception as e: logger.error(f"An error occurred: {str(e)}", exc_info=True) db.session.rollback() return ResponseHelper.internal_server_error() @staticmethod def process_calendar(data): try: with db.session.begin(): validated_data = AccountService.validate_data(data, UserSchema()) user_token = validated_data.get('token') uid = str(validated_data.get('uid')) member = Members.get_member_by_uid(uid) if not member: return { "error": 'Invalid Request', "uid": uid, }, 400 member_id = member.id dList = [] # LET get the ptovison actions prov_actions = ProvisionActions.get_provision_action_calendar_member_id(member_id=member_id, limit=100) if prov_actions: for prov_action in prov_actions: new_l = {"uid": prov_action.uid, "title": prov_action.action, "start": prov_action.added, "category": 3} dList.append(new_l) member_actions = MembersActions.get_recent_member_calendar_actions_member_id(member_id=member_id, limit=100) if member_actions: for member_action in member_actions: new_l = {"uid": member_action.uid, "title": member_action.action_label, "start": member_action.added, "category": 1} dList.append(new_l) # sample_range = random.randint(20, 60) # for x in range(sample_range): # timeMin = random.randint(1440, 2880) # calDate = datetime.datetime.utcnow() + datetime.timedelta(minutes=timeMin * random.randint(0, 20)) # new_l = {"uid": "425611f2-c692-4404-b93d-76ca7a5ce7" + str(x), # "title": "Calendar Random Item on " + str(x), "start": calDate, # "category": random.randint(1, 4)} # dList.append(new_l) calendar_data = { "last_update": datetime.datetime.utcnow(), "category": [ { "cid": "1", "description": "Health Check" }, { "cid": "2", "description": "Product Updates" }, { "cid": "3", "description": "Provisioning" }, { "cid": "4", "description": "Contacts" } ], "list": dList } return ResponseHelper.success(data=calendar_data) except ValidationError as err: logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.unprocessable_entity(result_description="Validation exception") except ValueError as err: logger.error(f"{getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.error(result_description=str(err)) except Exception as e: logger.error(f"An error occurred: {str(e)}", exc_info=True) db.session.rollback() return ResponseHelper.internal_server_error() @staticmethod def process_payments_data(data): try: with db.session.begin(): validated_data = AccountService.validate_data(data, UserSchema()) user_token = validated_data.get('token') uid = str(validated_data.get('uid')) member_data = Members.get_member_by_uid(uid) member_payments = Payments.get_member_payments_by_member_id(member_data.id) member_payments_data = [] for t in member_payments: member_payments_data.append({ 'id': t.id, 'uid': t.uid, 'option_name': t.option_name, 'option_type': t.option_type, 'payment_uid': t.payment_uid, 'amount': round(t.amount * 0.01, 2), 'status': t.status, 'added': t.added }) action_data = { "member_payments": member_payments_data, "last_update": datetime.datetime.utcnow(), } # logger.info(f"Member Actions : {action_data}") return ResponseHelper.success(data=action_data) except ValidationError as err: logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.unprocessable_entity(result_description="Validation exception") except ValueError as err: logger.error(f"{getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.error(result_description=str(err)) except Exception as e: logger.error(f"An error occurred: {str(e)}", exc_info=True) db.session.rollback() return ResponseHelper.internal_server_error() @staticmethod def process_profile_data(data): try: with db.session.begin(): validated_data = AccountService.validate_data(data, UserSchema()) user_token = validated_data.get('token') uid = str(validated_data.get('uid')) member_data = Members.get_member_by_uid(uid) file_url = BaseService.get_profile_picture_url(member_data.profile_picture) personal_data = { "firstname": member_data.firstname, "lastname": member_data.lastname, "account_name": member_data.account_name, "email": member_data.email, "phone": member_data.phone, "full_address": member_data.full_address, "picture": 'https://media.mermsemr.com/media/show/merms-profile' if file_url == '' else file_url, "country": member_data.country, } external_links = { "facebook_url": "facebook.com", "twitter_url": "twitter.com", "blogger_url": "blogger.com", "google_url": "google.com", "linked_url": "linkedin.com", "website_url": "www.mysite.com", } profile_data = { "personal_data": personal_data, "external_links": external_links, } return ResponseHelper.success(data=profile_data) except ValidationError as err: logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.unprocessable_entity(result_description="Validation exception") except ValueError as err: logger.error(f"{getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.error(result_description=str(err)) except Exception as e: logger.error(f"An error occurred: {str(e)}", exc_info=True) db.session.rollback() return ResponseHelper.internal_server_error() @staticmethod def update_profile_data(data): try: with db.session.begin(): validated_data = AccountService.validate_data(data, UserUpdateSchema()) user_token = validated_data.get('token') uid = str(validated_data.get('uid')) member_data = Members.get_member_by_uid(uid) if member_data: firstname = str(validated_data.get('firstname')) lastname = str(validated_data.get('lastname')) account_name = str(validated_data.get('account_name')) phone = str(validated_data.get('phone')) full_address = str(validated_data.get('full_address')) # email = str(validated_data.get('email')) profile_data = { "firstname": firstname, "lastname": lastname, "account_name": account_name, "phone": phone, "full_address": full_address, # "email": email, } Members.set_member_update_profile(uid, profile_data) # Read the saved data member_data = Members.get_member_by_uid(uid) personal_data = { "firstname": member_data.firstname, "lastname": member_data.lastname, "account_name": member_data.account_name, "email": member_data.email, "phone": member_data.phone, "full_address": member_data.full_address, "country": member_data.country, } external_links = { "facebook_url": "facebook.com", "twitter_url": "twitter.com", "blogger_url": "blogger.com", "google_url": "google.com", "linked_url": "linkedin.com", "website_url": "www.mysite.com", } profile_data = { "personal_data": personal_data, "external_links": external_links, } return ResponseHelper.success(data=profile_data) except ValidationError as err: logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.unprocessable_entity(result_description="Validation exception") except ValueError as err: logger.error(f"{getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.error(result_description=str(err)) except Exception as e: logger.error(f"An error occurred: {str(e)}", exc_info=True) db.session.rollback() return ResponseHelper.internal_server_error() @staticmethod def update_profile_link_data(data): try: with db.session.begin(): url_list = data["url_list"] data.pop("url_list") validated_data = AccountService.validate_data(data, ProfileLinksSchema()) user_token = validated_data.get('token') uid = str(validated_data.get('uid')) member_data = Members.get_member_by_uid(uid) if member_data: for key in url_list.keys(): url_list_value = url_list[key] logger.info(f"URL LIST : {key} : {url_list_value}") # # firstname = str(validated_data.get('firstname')) # lastname = str(validated_data.get('lastname')) # account_name = str(validated_data.get('account_name')) # phone = str(validated_data.get('phone')) # full_address = str(validated_data.get('full_address')) # # email = str(validated_data.get('email')) # profile_data = { # "firstname": firstname, # "lastname": lastname, # "account_name": account_name, # "phone": phone, # "full_address": full_address, # # "email": email, # } # Members.set_member_update_profile(uid, profile_data) # # Read the saved data # member_data = Members.get_member_by_uid(uid) # personal_data = { # "firstname": member_data.firstname, # "lastname": member_data.lastname, # "account_name": member_data.account_name, # "email": member_data.email, # "phone": member_data.phone, # "full_address": member_data.full_address, # "country": member_data.country, # } external_links = { "facebook_url": "https://facebook.com", "twitter_url": "twitter.com", "blogger_url": "blogger.com", "google_url": "google.com", "linked_url": "linkedin.com", "website_url": "www.mysite.com", } profile_data = { "external_links": external_links, } return ResponseHelper.success(data=profile_data) except ValidationError as err: logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.unprocessable_entity(result_description="Validation exception") except ValueError as err: logger.error(f"{getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.error(result_description=str(err)) except Exception as e: logger.error(f"An error occurred: {str(e)}", exc_info=True) db.session.rollback() return ResponseHelper.internal_server_error() @staticmethod def process_test_email(data): logger.info(f"Email Test Enter 001", exc_info=True) send_email_ses( to_email="ameye@chiefsoft.com", subject="Test from Merms", html_content="Hello from AWS SES" ) # AccountService.test_new_mailer() # AccountService.send_register_mail('ameye@chiefsoft.com', 'pend-uid---', 100, 'olutest', 'Ameyetest') logger.info(f"Email Test", exc_info=True) @staticmethod def test_new_mailer_old(): logger.info("test_new_mailer 000 ") # --- Email Configuration --- sender_email = "support@mermsemr.com" # Enter your email address receiver_email = "ameye@chiefsoft.com" # Enter the recipient's address # Use the App Password generated in Step 1 app_password = "flhf cjjx bguv fycg" app_password = "flhfcjjxbguvfycg" # --- Create the Email Message --- # msg = EmailMessage() # msg.set_content("This is the body of the email sent from Python.") msg = MIMEText("This is the body of my email.") msg['Subject'] = "Subject Line from Python" msg['From'] = sender_email msg['To'] = receiver_email # --- Connect to Gmail's SMTP Server and Send the Email --- smtp_server = "smtp.gmail.com" port = 587 # STARTTLS context = ssl.create_default_context() logger.info("test_new_mailer 003 ") try: logger.info("test_new_mailer 000 44") with smtplib.SMTP(smtp_server, port) as server: logger.info("test_new_mailer 000 44-1") server.ehlo() logger.info("test_new_mailer 000 44-2") server.starttls(context=context) server.ehlo() logger.info("test_new_mailer 000 55") server.login(sender_email, app_password) logger.info("test_new_mailer 000 66") server.send_message(msg) logger.info("test_new_mailer 000 77") logger.info("Email sent successfully!") except smtplib.SMTPAuthenticationError: logger.error("Authentication error: Check your username and password.") except smtplib.SMTPConnectError as e: logger.error(f"Connection error: {e}") except smtplib.SMTPException as e: logger.error(f"An unexpected SMTP error occurred: {e}") except Exception as e: logger.error(f"An unrelated error occurred: {e}") @staticmethod def test_new_mailer(): # Replace these with your actual details SENDGRID_API_KEY = "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" FROM_EMAIL = 'support@mermsemr.com' # Must be a verified sender in SendGrid TO_EMAIL = 'works@chiefsoft.com' message = Mail( from_email=FROM_EMAIL, to_emails=TO_EMAIL, subject='Sending with Twilio SendGrid is Fun', html_content='and easy to do anywhere, even with Python' ) try: # Initialize the SendGrid client sg = SendGridAPIClient(SENDGRID_API_KEY) # Send the email response = sg.send(message) # Print status codes: 202 means the request was accepted for delivery print(f"Status Code: {response.status_code}") print(f"Body: {response.body}") print(f"Headers: {response.headers}") except Exception as e: logger.error(f"An unrelated error occurred: {e}") # logger.info("test_new_mailer 000 ") # # --- Email Configuration --- # sender_email = "support@mermsemr.com" # Enter your email address # receiver_email = "ameye@chiefsoft.com" # Enter the recipient's address # # Use the App Password generated in Step 1 # app_password = "flhf cjjx bguv fycg" # app_password = "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" # # # --- Create the Email Message --- # # msg = EmailMessage() # # msg.set_content("This is the body of the email sent from Python.") # msg = MIMEText("This is the body of my email.") # msg['Subject'] = "Subject Line from Python" # msg['From'] = sender_email # msg['To'] = receiver_email # # # --- Connect to Gmail's SMTP Server and Send the Email --- # smtp_server = "smtp.sendgrid.net" # port = 587 # STARTTLS # # context = ssl.create_default_context() # logger.info("test_new_mailer 003 ") # try: # logger.info("test_new_mailer 000 44") # with smtplib.SMTP(smtp_server, port) as server: # logger.info("test_new_mailer 000 44-1") # server.ehlo() # logger.info("test_new_mailer 000 44-2") # server.starttls(context=context) # server.ehlo() # logger.info("test_new_mailer 000 55") # server.login(sender_email, app_password) # logger.info("test_new_mailer 000 66") # server.send_message(msg) # logger.info("test_new_mailer 000 77") # logger.info("Email sent successfully!") # # except smtplib.SMTPAuthenticationError: # logger.error("Authentication error: Check your username and password.") # # except smtplib.SMTPConnectError as e: # logger.error(f"Connection error: {e}") # except smtplib.SMTPException as e: # logger.error(f"An unexpected SMTP error occurred: {e}") # except Exception as e: # logger.error(f"An unrelated error occurred: {e}") def send_register_mail(signup_email, pending_uid, pending_id, firstname, lastname): pending_member = { "email": signup_email, "pending_uid": pending_uid, "first_name": firstname, "last_name": lastname, "pending_id": pending_id, } jwt_part = jwt.encode( {"user": pending_member, 'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=3330)}, AccountService.JWT_SECRET_KEY, algorithm='HS256' ) panel_url = panel_url = AccountService.THIS_SITE_URL # "https://qa-panel.mermsemr.com" link_url = str(panel_url) + '/csignup/' + jwt_part msg_body = f""" Hello {firstname}, You received this message for account verification Follow the link:{link_url} For any Support Reach Out support@mermsemr.com """ sender_email = AccountService.SEND_EMAIL_FROM sender_password = AccountService.SEND_EMAIL_PASS receiver_email = signup_email subject = "Verify your MERMS(AI) Account Setup" body = msg_body html_body = f"""\
|
| Hello {firstname}! |
|
You have received this message for your account verification |
|
Follow the link: link to complete the verification process. |