diff --git a/api_docs.yml b/api_docs.yml index dbab351f..23c2206c 100644 --- a/api_docs.yml +++ b/api_docs.yml @@ -581,6 +581,36 @@ paths: 500: description: "Internal Server Error" + "/users/inactive_user_reminder": + post: + tags: + - inactive_user_reminder + consumes: + - application/json + parameters: + - in: header + name: Authorization + required: true + description: "Bearer [token]" + - in: body + name: inactive_user_reminder + schema: + type: object + required: + - inactive_users + properties: + inactive_users: + type: array + produces: + - application/json + responses: + 201: + description: "Success" + 400: + description: "Bad request" + 500: + description: "Internal Server Error" + "/clusters": post: tags: diff --git a/app/controllers/__init__.py b/app/controllers/__init__.py index b26e8eb9..6afb6d35 100644 --- a/app/controllers/__init__.py +++ b/app/controllers/__init__.py @@ -4,7 +4,7 @@ from .users import ( UsersView, UserLoginView, UserEmailVerificationView, EmailVerificationRequest, ForgotPasswordView, ResetPasswordView, - UserDetailView, AdminLoginView, OAuthView, UserDataSummaryView, UserAdminUpdateView, UserActivitesView, InActiveUsersView) + UserDetailView, AdminLoginView, OAuthView, UserDataSummaryView, UserAdminUpdateView, UserActivitesView, InActiveUsersView, SendInactiveUserMailReminder) from .deployments import DeploymentsView from .clusters import ( ClustersView, ClusterDetailView, ClusterNamespacesView, diff --git a/app/controllers/users.py b/app/controllers/users.py index 0525d2b5..13d6df2e 100644 --- a/app/controllers/users.py +++ b/app/controllers/users.py @@ -9,6 +9,7 @@ from app.models.role import Role from app.helpers.confirmation import send_verification from app.helpers.token import validate_token +from app.helpers.inactive_notification import send_inactive_notification_to_user from app.schemas import ProjectSchema, AppSchema from app.helpers.decorators import admin_required import requests @@ -1097,3 +1098,58 @@ def get(self): status='success', data=dict(pagination=pagination, users=json.loads(users_data)) ), 200 + +class SendInactiveUserMailReminder(Resource): + + @admin_required + def post(self): + # Get the list of inactive users from the request body + user_schema = UserSchema() + + user_data = request.get_json() + + validated_user_data, errors = user_schema.load(user_data) + + today = datetime.now() + + if errors: + return dict(status="fail", message=errors), 400 + + if 'inactive_users' not in validated_user_data: + return dict(status='fail', message='Inactive users data not provided in the request'), 400 + + inactive_users = validated_user_data['inactive_users'] + + for user_data in inactive_users: + user = User.query.get(user_data['uuid']) # Assuming there's a unique identifier like 'id' + + if user is None: + continue + + # Check if a reminder email was sent in the last month + if user.last_reminder_sent is None or user.last_reminder_sent < (datetime.now() - timedelta(days=30)): + + # send email variable + name = user.name + template = "user/inactive_user_reminder.html" + subject = "We miss you at Crane Cloud" + email =user.email + today = today.date + success = False + + # send email + success = True + send_inactive_notification_to_user( + email, + name, + current_app._get_current_object(), + template, + subject, + today.strftime("%m/%d/%Y"), + success) + + user.last_reminder_sent = today.date() + db.session.commit() + + return dict(status='success', message='Reminder emails sent successfully') + \ No newline at end of file diff --git a/app/helpers/inactive_notification.py b/app/helpers/inactive_notification.py new file mode 100644 index 00000000..9ac6edb3 --- /dev/null +++ b/app/helpers/inactive_notification.py @@ -0,0 +1,15 @@ +from flask import render_template +from .email import send_email +from flask import Flask, request + + +def send_inactive_notification_to_user( email, name, app, template, subject, date, success): + client_base_url = f'https://{request.host}' + html = render_template(template, + email=email, + client_base_url=client_base_url, + name=name, + date= date, + success=success) + subject = subject + send_email(email, subject, html, email, app) \ No newline at end of file diff --git a/app/models/user.py b/app/models/user.py index 6014d1b6..7388645b 100644 --- a/app/models/user.py +++ b/app/models/user.py @@ -26,6 +26,7 @@ class User(ModelMixin): verified = db.Column(db.Boolean, nullable=False, default=False) date_created = db.Column(db.DateTime, default=db.func.current_timestamp()) last_seen = db.Column(db.DateTime, default=db.func.current_timestamp()) + last_reminder_sent = db.Column(db.DateTime, default=db.func.current_timestamp()) projects = db.relationship('Project', backref='owner', lazy=True) organisation = db.Column(db.String(256), nullable=True, default="") other_projects = db.relationship('ProjectUser', back_populates='user') diff --git a/app/routes/__init__.py b/app/routes/__init__.py index 067fe6bb..e0a94225 100644 --- a/app/routes/__init__.py +++ b/app/routes/__init__.py @@ -1,6 +1,6 @@ from flask_restful import Api from app.controllers import ( - IndexView, UsersView, UserLoginView, OAuthView, DeploymentsView, RolesView, InActiveUsersView, + IndexView, UsersView, UserLoginView, OAuthView, DeploymentsView, RolesView, InActiveUsersView, SendInactiveUserMailReminder, RolesDetailView, CreditAssignmentView, CreditAssignmentDetailView, CreditView, UserRolesView, UserDataSummaryView, ClustersView, ClusterDetailView, ClusterNamespacesView, ClusterNamespaceDetailView, ClusterNodesView, ClusterNodeDetailView, @@ -43,7 +43,8 @@ api.add_resource(UserActivitesView, '/users/activities') api.add_resource(InActiveUsersView, '/users/inactive_users', endpoint='inactive_users') - +api.add_resource(SendInactiveUserMailReminder, '/users/inactive_user_reminder', + endpoint='inactive_user_reminder') # Deployments api.add_resource(DeploymentsView, '/deployments', endpoint='deployments') diff --git a/templates/user/inactive_user_reminder.html b/templates/user/inactive_user_reminder.html new file mode 100644 index 00000000..998a2ebd --- /dev/null +++ b/templates/user/inactive_user_reminder.html @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + +
We're thrilled to have you here! Get ready to dive into your new account.
+ + + + + + + +
+ + + + +
+ +

{{ name }}

+
+
+ + + + + + + + + + + +
+

We miss you at Crane Cloud. Get ready to dive into your account. Let's help you get started. Just press the button below.

+
+ + + + +
+ + + + +
Visit Crane Cloud +
+
+
+

Cheers!
Crane Cloud Team

+
+
+ + +