rset [pass

This commit is contained in:
CHIEFSOFT\ameye
2025-07-12 00:19:58 -04:00
parent 69b5e3e3b2
commit 4e9d500337
7 changed files with 205 additions and 46 deletions
+1 -13
View File
@@ -1,20 +1,8 @@
from app import create_app from app import create_app
from flask_mail import Mail, Message from flask_mail import Mail, Message
from app.config import Config # from app.config import Config
app = create_app() app = create_app()
if __name__ == "__main__": if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True) app.run(host="0.0.0.0", port=5000, debug=True)
mail = Mail(app) # instantiate the mail class
# configuration of mail
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 465
# app.config['MAIL_PORT'] = 587
app.config['MAIL_USERNAME'] = 'message@chiefsoft.com'
app.config['MAIL_PASSWORD'] = 'may12002!'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
mail = Mail(app)
+9
View File
@@ -47,6 +47,15 @@ def serve_paths(filename):
swagger_dir = os.path.join("swagger") swagger_dir = os.path.join("swagger")
return send_from_directory(swagger_dir, filename) return send_from_directory(swagger_dir, filename)
@api.route("/panel/auth/reset", methods=["POST"])
@jwt_required()
def merms_reset():
data = request.get_json()
response = LoginService.process_reset(data)
return response
@api.route("/panel/Login", methods=["POST"]) @api.route("/panel/Login", methods=["POST"])
@jwt_required() @jwt_required()
def merms_login(): def merms_login():
+4
View File
@@ -0,0 +1,4 @@
from marshmallow import Schema, fields
class ResetPassStart(Schema):
username = fields.Str(required=True)
+68 -1
View File
@@ -4,11 +4,78 @@ from flask import jsonify
from marshmallow import ValidationError from marshmallow import ValidationError
import logging import logging
from app.api.integrations import KafkaIntegration from app.api.integrations import KafkaIntegration
from app.config import Config
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
from flask_mail import Mail, Message
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
class BaseService: class BaseService:
TRANSACTION_TYPE = None TRANSACTION_TYPE = None
JWT_SECRET_KEY = Config.JWT_SECRET_KEY
SEND_EMAIL_FROM = Config.SEND_EMAIL_FROM
SEND_EMAIL_PASS = Config.SEND_EMAIL_PASS
@staticmethod
def send_resetpass_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)},
BaseService.JWT_SECRET_KEY, algorithm='HS256'
)
panel_url = "https://qa-panel.mermsemr.com"
link_url = str(panel_url) + '/accreset/' + jwt_part
msg_body = f"""
Hello {firstname},
You received this message for account reset password
Follow the link:{link_url}
For any Support
Reach Out
support@mermsemr.com
"""
sender_email = BaseService.SEND_EMAIL_FROM
sender_password = BaseService.SEND_EMAIL_PASS
receiver_email = signup_email
subject = "Reset Password Email"
body = msg_body
msg = MIMEMultipart()
msg['Subject'] = subject
msg['From'] = sender_email
msg['To'] = receiver_email
msg.attach(MIMEText(body, 'plain')) # or 'html' for HTML content
try:
# For Gmail, use 'smtp.gmail.com' and port 587 (TLS) or 465 (SSL)
# For other providers, consult their documentation for SMTP server and port
server = smtplib.SMTP('smtp.gmail.com', 587)
# server.starttls() # Enable TLS encryption
server.login(sender_email, sender_password)
server.sendmail(sender_email, receiver_email, msg.as_string())
print("Email sent successfully!")
except Exception as e:
print(f"Error sending email: {e}")
logger.error(f"Error sending email: {e}")
finally:
server.quit() # Close the connection
@classmethod @classmethod
def validate_data(cls, data, schema): def validate_data(cls, data, schema):
+73 -31
View File
@@ -1,17 +1,18 @@
from flask import session, jsonify from flask import session, jsonify
from app.models.loan import Loan #from app.models.loan import Loan
from app.utils.logger import logger from app.utils.logger import logger
from app.api.services.base_service import BaseService from app.api.services.base_service import BaseService
from app.api.schemas.eligibility_check import EligibilityCheckSchema # from app.api.schemas.eligibility_check import EligibilityCheckSchema
from marshmallow import ValidationError from marshmallow import ValidationError
from app.api.enums import TransactionType # from app.api.enums import TransactionType
from app.api.integrations import SimbrellaIntegration # from app.api.integrations import SimbrellaIntegration
from app.extensions import db from app.extensions import db
from app.models import Offer, RACCheck, Members from app.models import PasswordReset, Members
from app.api.services.offer_analysis import OfferAnalysis #from app.api.services.offer_analysis import OfferAnalysis
from app.api.helpers.response_helper import ResponseHelper from app.api.helpers.response_helper import ResponseHelper
from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.security import generate_password_hash, check_password_hash
from app.api.schemas.login import LoginSchema from app.api.schemas.login import LoginSchema
from app.api.schemas.reset_pass_start import ResetPassStart
import datetime import datetime
import jwt import jwt
import random import random
@@ -19,6 +20,47 @@ from app.config import Config
class LoginService(BaseService): class LoginService(BaseService):
@staticmethod
def process_reset(data):
try:
with db.session.begin():
validated_data = LoginService.validate_data(data, ResetPassStart())
username = validated_data.get('username')
member = Members.get_member_by_username(username)
if not member:
invalid_data = {
"error_message": "invalid username or password",
"message_key": "invalid_username_or_password",
}
return ResponseHelper.success(data=invalid_data)
PasswordReset.create_reset(username=username)
BaseService.send_resetpass_mail(member.email, member.uid, member.id, "FF","LL") #pending_uid, pending_id, firstname, lastname
response_data = {
"error_message": "invalid username or password 000",
"message_key": "invalid_username_or_password",
}
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 @staticmethod
def process_request(data): def process_request(data):
@@ -150,28 +192,28 @@ class LoginService(BaseService):
db.session.rollback() db.session.rollback()
return ResponseHelper.internal_server_error() return ResponseHelper.internal_server_error()
@staticmethod # @staticmethod
def check_loan_limits(customer_id): # def check_loan_limits(customer_id):
""" # """
Checks if a customer has exceeded the loan limits for given offer. # Checks if a customer has exceeded the loan limits for given offer.
""" # """
loan = Loan.get_customer_last_loan(customer_id) # loan = Loan.get_customer_last_loan(customer_id)
#
if not loan: # if not loan:
return True # return True
#
offer_id = loan.offer_id[:5] # offer_id = loan.offer_id[:5]
#
offer = Offer.get_offer_by_id(offer_id) # offer = Offer.get_offer_by_id(offer_id)
if not offer: # if not offer:
logger.error(f"Offer not found for offer_id: {offer_id} (customer_id: {customer_id})") # logger.error(f"Offer not found for offer_id: {offer_id} (customer_id: {customer_id})")
return False # return False
#
daily_count = Loan.get_daily_loan_count(customer_id, offer.product_id) # daily_count = Loan.get_daily_loan_count(customer_id, offer.product_id)
#
logger.info(f"daily_count: {daily_count}, Max: {offer.max_daily_loans}") # logger.info(f"daily_count: {daily_count}, Max: {offer.max_daily_loans}")
#
if offer.max_daily_loans is not None and daily_count >= offer.max_daily_loans: # if offer.max_daily_loans is not None and daily_count >= offer.max_daily_loans:
return False # return False
#
return True # return True
+3 -1
View File
@@ -18,8 +18,10 @@ from .members_actions import MembersActions
from .members_pending import MembersPending from .members_pending import MembersPending
from .products_details import ProductsDetails from .products_details import ProductsDetails
from .provision_actions import ProvisionActions from .provision_actions import ProvisionActions
from .password_reset import PasswordReset
__all__ = ['Members','Customer', 'Account', 'Products', __all__ = ['Members','Customer', 'Account', 'Products',
'MembersProducts', 'MembersActions', 'MembersPending', 'ProductsDetails', 'ProvisionActions', 'Loan', 'Transaction', 'Repayment', 'MembersProducts', 'MembersActions', 'MembersPending', 'ProductsDetails', 'ProvisionActions', 'PasswordReset','Loan', 'Transaction', 'Repayment',
'LoanCharge', 'Offer', 'Charge', 'RACCheck', 'LoanRepaymentSchedule', 'LoanCharge', 'Offer', 'Charge', 'RACCheck', 'LoanRepaymentSchedule',
'TransactionOffer', 'RepaymentsData', 'Salary'] 'TransactionOffer', 'RepaymentsData', 'Salary']
+47
View File
@@ -0,0 +1,47 @@
from datetime import datetime, timezone
from app.extensions import db
from app.models.charge import Charge
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from sqlalchemy.exc import IntegrityError
import uuid
from app.utils.logger import logger
class PasswordReset(db.Model):
__tablename__ = 'password_reset'
id = db.Column(db.String, primary_key=True)
uid = db.Column(db.String(150), nullable=True)
username = db.Column(db.String, nullable=False)
status = db.Column(db.Integer, nullable=True, default=0)
added = db.Column(db.DateTime(timezone=True), server_default=func.now())
updated = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
def to_dict(self):
return {
"id": self.id,
"uid": self.uid,
"username": self.account_id,
"status": self.status,
"added": self.added.isoformat() if self.added else None,
"updated": self.updated.isoformat() if self.updated else None,
}
def __repr__(self):
return f'<pPassReset {self.id} - {self.amount}>'
@classmethod
def create_reset(cls, username):
pass_reset = cls(
uid=str(uuid.uuid4()),
username=username,
created_at=datetime.now(timezone.utc),
updated_at=datetime.now(timezone.utc)
)
try:
db.session.add(pass_reset)
except IntegrityError as err:
raise ValueError(f"Database integrity error: {err}")
return pass_reset