Kaynağa Gözat

Correcting logic errors in the schedules and other parts of the application.

Adam Day 2 yıl önce
ebeveyn
işleme
2d0cbf0039

+ 110 - 21
app.py

@@ -71,9 +71,11 @@ class PasswordResetLog(Model):
 
 class EmailReminderLog(Model):
     date = CharField(default=datetime.datetime.now().strftime('%Y-%m-%d'))
+    username = CharField()
     email = CharField()
     interval = CharField()
     sent = BooleanField(default=False)
+    ignore = BooleanField(default=False)
 
     class Meta:
         database = db
@@ -81,6 +83,7 @@ class EmailReminderLog(Model):
 
 def scheduler(stop_event):
     while not stop_event.is_set():
+        db.connect()
         # Get all scheduled intervals from the DB
         intervals = Schedule.select().execute()
         users = IlsUser.select().execute()
@@ -123,16 +126,16 @@ def scheduler(stop_event):
                 email_date = password_expiration_date - datetime.timedelta(days=int(interval.interval))
 
                 # check if reminder has already been saved to the DB
-                reminder = EmailReminderLog.select().where(EmailReminderLog.email == user.email, EmailReminderLog.interval == interval.interval).execute()
+                reminder = EmailReminderLog.select().where(EmailReminderLog.date == email_date.strftime('%Y-%m-%d'), EmailReminderLog.username == user.username, EmailReminderLog.interval == interval.interval).execute()
                 if reminder:
                     continue
                 else:
                     # Store the date in the DB
-                    EmailReminderLog.create(date=email_date.strftime('%Y-%m-%d'), email=user.email, interval=interval.interval).save()
+                    EmailReminderLog.create(date=email_date.strftime('%Y-%m-%d'), email=user.email, username=user.username, interval=interval.interval).save()
 
         # Get all email reminders from the DB
         # if today's date matches the EmailReminderLog date then send the email and mark the reminder as sent
-        reminders = EmailReminderLog.select().where(EmailReminderLog.date == datetime.datetime.now().strftime('%Y-%m-%d')).execute()
+        reminders = EmailReminderLog.select().where(EmailReminderLog.date == datetime.datetime.now().strftime('%Y-%m-%d'), EmailReminderLog.ignore == False).execute()
         for reminder in reminders:
             # Send the email
             emailer = Emailer(smtp_host, smtp_port, smtp_username, smtp_password)
@@ -140,8 +143,8 @@ def scheduler(stop_event):
             # Mark the reminder as sent
             reminder.sent = True
             reminder.save()
-
-        time.sleep(5)  # Sleep for 15 minutes
+        db.close()
+        time.sleep(10)  # Sleep for 15 minutes
 
 
 # Encrypt the password with SHA256
@@ -300,7 +303,65 @@ def format_time_ago(timestamp):
     return "just now"
 
 
+# Create method for time until
+def format_time_until(timestamp):
+    """Calculate the time until a datetime stamp and format it as a human-readable string."""
+
+    # Convert timestap into datetime object
+    timestamp = datetime.datetime.strptime(timestamp, '%Y-%m-%d')
+
+    now = datetime.datetime.now()
+    diff = timestamp - now
+
+    if diff.days > 365:
+        years = diff.days // 365
+        return f"in {years} year{'s' if years > 1 else ''}"
+
+    # return months and days
+    if diff.days > 30:
+        months = diff.days // 30
+        days = diff.days % 30
+        return f"in {months} month{'s' if months > 1 else ''} and {days} day{'s' if days > 1 else ''}"
+
+    # return days
+    if diff.days > 0:
+        return f"in {diff.days} day{'s' if diff.days > 1 else ''}"
+
+    # return hours and minutes
+    if diff.seconds > 3600:
+        hours = diff.seconds // 3600
+        minutes = (diff.seconds % 3600) // 60
+        return f"in {hours} hour{'s' if hours > 1 else ''} and {minutes} minute{'s' if minutes > 1 else ''}"
+
+    # return minutes
+    if diff.seconds > 60:
+        minutes = diff.seconds // 60
+        return f"in {minutes} minute{'s' if minutes > 1 else ''}"
+
+    return "now"
+
+
+
+    if diff.days > 30:
+        months = diff.days // 30
+        return f"in {months} month{'s' if months > 1 else ''}"
+
+    if diff.days > 0:
+        return f"in {diff.days} day{'s' if diff.days > 1 else ''}"
+
+    if diff.seconds > 3600:
+        hours = diff.seconds // 3600
+        return f"in {hours} hour{'s' if hours > 1 else ''}"
+
+    if diff.seconds > 60:
+        minutes = diff.seconds // 60
+        return f"in {minutes} minute{'s' if minutes > 1 else ''}"
+
+    return "now"
+
+
 app.jinja_env.filters['time_since'] = format_time_ago
+app.jinja_env.filters['time_until'] = format_time_until
 
 
 @app.before_request
@@ -401,6 +462,12 @@ def admin():
     except Exception as e:
         ils_users = None
 
+    # Get a count of all EmailReminders that are not ignored or sent
+    try:
+        total_email_reminders = EmailReminderLog.select().where(EmailReminderLog.sent == False, EmailReminderLog.ignore == False).count()
+    except Exception as e:
+        total_email_reminders = None
+
     # Get a list of coming email reminders for the next 7 days
     try:
         email_reminders = PasswordResetLog.select().where(PasswordResetLog.date_created < datetime.datetime.now() + datetime.timedelta(days=7)).execute()
@@ -416,7 +483,7 @@ def admin():
     # get a list of email notifications sent in the last 7 days
     try:
         # Get a list of all future email reminders
-        email_reminders = EmailReminderLog.select().order_by(EmailReminderLog.date).limit(15).execute()
+        email_reminders = EmailReminderLog.select().order_by(-EmailReminderLog.date).limit(15).execute()
     except Exception as e:
         email_reminders = None
 
@@ -424,6 +491,7 @@ def admin():
         'ils_user_count': ils_users,
         'ils_users_expiring': ils_users_expiring,
         'email_reminders': email_reminders,
+        'total_email_reminders': total_email_reminders,
     }
 
     return render_template('admin.html', context=context)
@@ -578,10 +646,14 @@ def admin_ils_users_delete(id):
     user = IlsUser.get(IlsUser.id == id)
     username = user.username
 
-    # Remove all email reminders for this user
-    reminders = EmailReminderLog.select().where(EmailReminderLog.email == user.email).execute()
-    for reminder in reminders:
-        reminder.delete_instance()
+    # Remove scheduled email reminders
+    try:
+        email_reminders = EmailReminderLog.select().where(EmailReminderLog.username == user.username).execute()
+        for reminder in email_reminders:
+            reminder.delete_instance()
+        print('here')
+    except Exception as e:
+        print('there', e)
 
     user.delete_instance()
     Log.create(username=session['username'], action='Removed ILS user: %s' % username, ).save()
@@ -612,6 +684,16 @@ def admin_ils_users_edit(id):
         if username in all_users:
             message = 'Username already exists'
         else:
+            # Update Scheduled Email reminders
+            try:
+                email_reminders = EmailReminderLog.select().where(EmailReminderLog.username == user.username).execute()
+                for reminder in email_reminders:
+                    reminder.username = username
+                    reminder.email = email
+                    reminder.save()
+            except Exception as e:
+                print(e)
+
             user.username = username
             user.email = email
             user.save()
@@ -800,7 +882,7 @@ def schedule():
             Log.create(username=session['username'], action='Created schedule for %s day interval.' % interval).save()
             message = 'Schedule: %s created successfully' % interval
 
-
+    schedules = Schedule.select().order_by(Schedule.interval.cast("INTEGER")).execute()
 
     context = {
         'schedules': schedules,
@@ -817,7 +899,7 @@ def scheduled_emails():
         return redirect(url_for('login'))
 
     # Get all future emailreminderlogs
-    reminders = EmailReminderLog.select().where(EmailReminderLog.date > datetime.datetime.now()).order_by(
+    reminders = EmailReminderLog.select().where(EmailReminderLog.date > datetime.datetime.now(), EmailReminderLog.ignore == False).order_by(
         -EmailReminderLog.date).execute()
 
     context = {
@@ -837,8 +919,10 @@ def reminder_remove(id):
     # Get EmailReminderLogs with the interval of the schedule being removed
     email_reminder_log = EmailReminderLog.get(EmailReminderLog.id == id)
     Log.create(username=session['username'],
-               action='Removed %s day reminder for %s' % (email_reminder_log.interval, email_reminder_log.email)).save()
-    email_reminder_log.delete_instance()
+               action='Removed %s day reminder for %s (%s)' % (email_reminder_log.interval, email_reminder_log.username, email_reminder_log.email)).save()
+    email_reminder_log.ignore = True
+    email_reminder_log.save()
+
     return redirect(url_for('scheduled_emails'))
 
 
@@ -849,14 +933,19 @@ def schedule_remove(id):
     if not requires_auth():
         return redirect(url_for('login'))
 
-    # Get EmailReminderLogs with the interval of the schedule being removed
-    email_reminder_logs = EmailReminderLog.select().where(EmailReminderLog.interval == id).execute()
-    for email_reminder_log in email_reminder_logs:
-        email_reminder_log.delete_instance()
+    # Get Schedule by id
+    try:
+        schedule = Schedule.get(Schedule.id == id)
+    except Exception as e:
+        schedule = None
+
+    if schedule:
+        # Get EmailReminderLogs with the interval of the schedule being removed
+        email_reminder_logs = EmailReminderLog.select().where(EmailReminderLog.interval == schedule.interval).execute()
+        for email_reminder_log in email_reminder_logs:
+            email_reminder_log.delete_instance()
 
-    # Get the schedule from the DB
-    schedule = Schedule.get(Schedule.id == id)
-    schedule.delete_instance()
+        schedule.delete_instance()
 
     Log.create(username=session['username'], action='Removed schedule for a %s day reminder.' % schedule.interval).save()
     return redirect(url_for('schedule'))

+ 3 - 0
static/app.css

@@ -0,0 +1,3 @@
+.tooltip-inner {
+    max-width: 100% !important;
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 4 - 0
static/bootstrap-5.3.0-alpha1-dist/js/popper.min.js


+ 19 - 8
templates/admin.html

@@ -5,16 +5,25 @@
         <h3 class="mb-3"><i class="ri-dashboard-fill"></i> Admin Dashboard</h3>
         <div class="row justify-content-center">
 
-            <div class="col-sm-12 mb-4">
+            <div class="col-sm-12 col-md-6 mb-4">
                 <div class="card">
                     <div class="card-body text-center">
                         <h4>ILS User Count</h4>
-                        <h1 class="display-3">{{ context.ils_user_count}}</h1>
+                        <h1 class="display-3">{{ context.ils_user_count }}</h1>
                     </div>
                 </div>
             </div>
 
             <div class="col-sm-12 col-md-6 mb-4">
+                <div class="card">
+                    <div class="card-body text-center">
+                        <h4>Scheduled Reminders</h4>
+                        <h1 class="display-3">{{ context.total_email_reminders }}</h1>
+                    </div>
+                </div>
+            </div>
+
+            <div class="col-sm-12 col-md-4 mb-4">
                 <div class="card">
                     <div class="card-body text-center">
                         <h4>Expiring in 7 days</h4>
@@ -25,19 +34,21 @@
                 </div>
             </div>
 
-            <div class="col-sm-12 col-md-6 mb-4">
+            <div class="col-sm-12 col-md-8 mb-4">
                 <div class="card">
                     <div class="card-body text-center">
                         <h4>Upcoming Reminders</h4>
-                        <table class="table text-start">
+                        <table class="table table-hover text-start">
                             <tr>
-                                <th>Email</th>
+                                <th>ILS User</th>
+                                <th>Reminder Type</th>
                                 <th>Send on</th>
                             </tr>
                             {% for reminder in context.email_reminders %}
-                                <tr>
-                                    <td>{{ reminder.email }}</td>
-                                    <td>{{ reminder.date }}</td>
+                                <tr data-bs-toggle="tooltip" data-bs-placement="right" data-container="body" title="{{ reminder.email }}">
+                                    <td>{{ reminder.username }}</td>
+                                    <td>{{ reminder.interval }} day reminder</td>
+                                    <td>{{ reminder.date }} {{ reminder.date | time_until }}</td>
                                 </tr>
                             {% endfor %}
                         </table>

+ 9 - 3
templates/auth_layout.html

@@ -5,7 +5,9 @@
     <title>ILS Password Manager</title>
     <link rel="stylesheet" href="{{ url_for('static', filename='bootstrap-5.3.0-alpha1-dist/css/bootstrap.css') }}">
     <link rel="stylesheet" href="{{ url_for('static', filename='RemixIcon_Fonts_v2.5.0/fonts/remixicon.css') }}">
+    <link rel="stylesheet" href="{{ url_for('static', filename='app.css') }}">
     <script src="{{ url_for('static', filename='bootstrap-5.3.0-alpha1-dist/js/bootstrap.bundle.js') }}"></script>
+    <script src="{{ url_for('static', filename='bootstrap-5.3.0-alpha1-dist/js/popper.min.js') }}"></script>
 </head>
 <body>
     <div class="container mb-5">
@@ -26,9 +28,6 @@
                     <li class="nav-item">
                         <a class="nav-link bg-light text-dark border-bottom" href="{{ url_for('admin_ils_users') }}"><i class="ri-shield-user-fill"></i> ILS Users</a>
                     </li>
-                    <li class="nav-item">
-                        <a class="nav-link bg-light text-dark border-bottom" href="{{ url_for('settings') }}"><i class="ri-settings-5-line"></i> Settings</a>
-                    </li>
                     <li class="nav-item">
                         <a class="nav-link bg-light text-dark border-bottom" href="{{ url_for('schedule') }}"><i class="ri-time-line"></i> Schedule</a>
                     </li>
@@ -38,6 +37,9 @@
                     <li class="nav-item">
                         <a class="nav-link bg-light text-dark border-bottom" href="{{ url_for('password_reset_log') }}"><i class="ri-file-list-3-line"></i> Password Reset Log</a>
                     </li>
+                    <li class="nav-item">
+                        <a class="nav-link bg-light text-dark border-bottom" href="{{ url_for('settings') }}"><i class="ri-settings-5-line"></i> Settings</a>
+                    </li>
                     <li class="nav-item">
                         <a class="nav-link bg-danger text-white border-bottom" href="{{ url_for('logout') }}"><i class="ri-logout-box-line"></i> Logout</a>
                     </li>
@@ -48,5 +50,9 @@
             </div>
         </div>
     </div>
+    <script>
+        const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
+        const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
+    </script>
 </body>
 </html>

+ 3 - 1
templates/scheduled_emails.html

@@ -21,6 +21,7 @@
                 <tr>
                     <th scope="col">Date to Send</th>
                     <th scope="col">Days before expiration</th>
+                    <th scope="col">Username</th>
                     <th scope="col">Email</th>
                     <th class="text-end" scope="col">Actions</th>
                 </tr>
@@ -28,8 +29,9 @@
             <tbody>
                 {% for reminder in context.reminders %}
                 <tr>
-                    <td>{{ reminder.date }}</td>
+                    <td>{{ reminder.date }} {{ reminder.date | time_until }}</td>
                     <td>{{ reminder.interval }}</td>
+                    <td>{{ reminder.username }}</td>
                     <td>{{ reminder.email }}</td>
                     <td class="text-end">
                         <a href="#!" data-bs-toggle="modal" data-bs-target="#reminder-{{ loop.index0 }}" class="btn btn-danger">Delete</a>

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor