fixes quota recalculation
This commit is contained in:
parent
74e713e8a6
commit
243e24e100
@ -49,6 +49,19 @@ def _update_volume(new_volume):
|
||||
)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
# Invalidate and recalculate the hourly quota cache
|
||||
try:
|
||||
# Import the calculation function from the scraper module
|
||||
from ..blueprints.scraper import calculate_papers_for_current_hour
|
||||
invalidate_hourly_quota_cache(calculate_papers_for_current_hour)
|
||||
except Exception as e:
|
||||
# Log the error but don't fail the update
|
||||
ActivityLog.log_error(
|
||||
error_message=f"Error invalidating hourly quota cache: {str(e)}",
|
||||
source="_update_volume"
|
||||
)
|
||||
|
||||
return True, "Volume updated successfully!", volume_config
|
||||
|
||||
except (ValueError, TypeError) as e:
|
||||
@ -175,9 +188,11 @@ def _update_schedule(schedule_data):
|
||||
|
||||
db.session.commit()
|
||||
|
||||
# Invalidate hourly quota cache using the cache_utils module
|
||||
# Invalidate hourly quota cache and immediately recalculate
|
||||
try:
|
||||
invalidate_hourly_quota_cache()
|
||||
# Import the calculation function from the scraper module
|
||||
from ..blueprints.scraper import calculate_papers_for_current_hour
|
||||
invalidate_hourly_quota_cache(calculate_papers_for_current_hour)
|
||||
except Exception as e:
|
||||
# Log the error but don't fail the update
|
||||
ActivityLog.log_error(
|
||||
|
@ -12,17 +12,37 @@ HOURLY_QUOTA_CACHE = {
|
||||
'last_config_update': None, # Last time volume or schedule config was updated
|
||||
}
|
||||
|
||||
def invalidate_hourly_quota_cache():
|
||||
"""Invalidate the hourly quota cache when configuration changes."""
|
||||
def invalidate_hourly_quota_cache(calculate_function=None):
|
||||
"""
|
||||
Invalidate the hourly quota cache when configuration changes.
|
||||
|
||||
Args:
|
||||
calculate_function (callable, optional): Function to recalculate quota immediately.
|
||||
If None, recalculation will happen during next get_cached_hourly_quota() call.
|
||||
"""
|
||||
global HOURLY_QUOTA_CACHE
|
||||
HOURLY_QUOTA_CACHE['last_config_update'] = None
|
||||
|
||||
# Log the cache invalidation
|
||||
ActivityLog.log_scraper_activity(
|
||||
action="cache_invalidated",
|
||||
status="info",
|
||||
description="Hourly quota cache was invalidated due to configuration changes"
|
||||
)
|
||||
# If a calculation function is provided, recalculate immediately
|
||||
if calculate_function:
|
||||
current_hour = datetime.now().hour
|
||||
quota = calculate_function()
|
||||
HOURLY_QUOTA_CACHE['hour'] = current_hour
|
||||
HOURLY_QUOTA_CACHE['quota'] = quota
|
||||
HOURLY_QUOTA_CACHE['last_config_update'] = datetime.now()
|
||||
|
||||
ActivityLog.log_scraper_activity(
|
||||
action="cache_recalculated",
|
||||
status="info",
|
||||
description=f"Hourly quota immediately recalculated after config change: {quota} papers"
|
||||
)
|
||||
else:
|
||||
# Log the cache invalidation
|
||||
ActivityLog.log_scraper_activity(
|
||||
action="cache_invalidated",
|
||||
status="info",
|
||||
description="Hourly quota cache was invalidated due to configuration changes"
|
||||
)
|
||||
|
||||
def get_cached_hourly_quota(calculate_function):
|
||||
"""
|
||||
|
@ -30,6 +30,13 @@
|
||||
font-size: 0.7rem;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.weight-gradient {
|
||||
width: 50px;
|
||||
height: 15px;
|
||||
background: linear-gradient(to right, hsl(210, 10%, 95%), hsl(210, 10%, 30%));
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@ -39,86 +46,168 @@
|
||||
|
||||
<div x-data="scheduleManager(initialSchedule, totalVolume)" class="tab-pane active">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-header d-flex justify-content-between">
|
||||
<h5>Scheduling Configuration</h5>
|
||||
<span>
|
||||
<button class="btn btn-sm btn-outline-secondary" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#helpContent">
|
||||
<i class="fas fa-question-circle"></i> Help
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<!-- include flash messages template -->
|
||||
{% include "partials/flash_messages.html.jinja" %}
|
||||
|
||||
<!-- Content -->
|
||||
<div class="mb-3">
|
||||
<h3>How it Works</h3>
|
||||
<p class="text-muted mb-0">
|
||||
This page allows you to configure the daily volume of papers to be
|
||||
downloaded and the hourly download weights for the papers. The weights
|
||||
determine how many papers will be downloaded during each hour of the day.
|
||||
The total volume (<strong x-text="volume"></strong> papers/day) is split
|
||||
across all hours based on their relative weights. Each weight controls the
|
||||
proportion of papers downloaded during that hour. Click to select one or
|
||||
more hours below. Then assign a weight to them using the input and apply
|
||||
it. Color indicates relative intensity. The total daily volume will be
|
||||
split proportionally across these weights.
|
||||
<strong>Don't forget to submit the changes!</strong>
|
||||
</p>
|
||||
<h3>Example</h3>
|
||||
<p class="text-muted mb-0">
|
||||
If the total volume is <strong>240 papers</strong> and hours are
|
||||
<strong>weighted as 1.0, 2.0, and 3.0</strong>, they will receive
|
||||
<strong>40, 80, and 120 papers</strong> respectively.
|
||||
</p>
|
||||
</div>
|
||||
<!-- Collapsible Help Content -->
|
||||
<div class="collapse mt-3" id="helpContent">
|
||||
<div class="card card-body">
|
||||
<ul class="nav nav-tabs" id="helpTabs" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="calculation-tab" data-bs-toggle="tab"
|
||||
data-bs-target="#calculation" type="button">Calculation</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="usage-tab" data-bs-toggle="tab" data-bs-target="#usage"
|
||||
type="button">Usage</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="example-tab" data-bs-toggle="tab" data-bs-target="#example"
|
||||
type="button">Example</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content p-3 border border-top-0 rounded-bottom">
|
||||
<!-- Calculation Tab -->
|
||||
<div class="tab-pane fade show active" id="calculation" role="tabpanel">
|
||||
<h5>Quota Calculation</h5>
|
||||
<p>Each hour's quota is calculated as:</p>
|
||||
<div class="bg-light p-2 mb-2 rounded">
|
||||
<code>Papers per hour = (Hour Weight ÷ Total Weight) × Daily Volume</code>
|
||||
</div>
|
||||
<p class="small mb-0">Changes to either volume or schedule weights will immediately
|
||||
recalculate all hourly quotas.</p>
|
||||
</div>
|
||||
|
||||
<h2 class="mt-4">Volume</h2>
|
||||
<!-- Usage Instructions Tab -->
|
||||
<div class="tab-pane fade" id="usage" role="tabpanel">
|
||||
<h5>Usage Instructions</h5>
|
||||
<ol class="mb-0">
|
||||
<li>Click to select one or more hour blocks (use drag to select multiple)</li>
|
||||
<li>Adjust the weight value for selected hours (0.1-5.0)</li>
|
||||
<li>Click "Apply to Selected" to set the weights</li>
|
||||
<li>Click "Save Schedule" to commit your changes</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="align-items-start flex-wrap gap-2">
|
||||
<p class="text-muted">
|
||||
The total volume of data to be downloaded each day is
|
||||
<strong x-text="volume"></strong> papers.
|
||||
</p>
|
||||
<div class="d-flex align-items-center mb-3" x-data="{ volumeValue: volume }">
|
||||
<div class="input-group w-50">
|
||||
<label class="input-group-text">Papers per day:</label>
|
||||
<input type="number" class="form-control" x-model="volumeValue" min="1" max="{{ max_volume }}"
|
||||
required />
|
||||
<button type="button" class="btn btn-primary" @click="updateVolume()">
|
||||
Update Volume
|
||||
</button>
|
||||
<!-- Example Tab -->
|
||||
<div class="tab-pane fade" id="example" role="tabpanel">
|
||||
<h5>Example</h5>
|
||||
<p class="mb-0">
|
||||
With a daily volume of <strong>240 papers</strong> and hour weights of
|
||||
<strong>1.0, 2.0, and 3.0</strong>, the distribution will be
|
||||
<strong>40, 80, and 120 papers</strong> respectively
|
||||
(based on ratios 1:2:3 of the total weight 6.0).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="mt-4">Current Schedule</h2>
|
||||
<form x-data id="scheduleForm">
|
||||
<div class="timeline mb-3" @mouseup="endDrag()" @mouseleave="endDrag()">
|
||||
<template x-for="hour in Object.keys(schedule)" :key="hour">
|
||||
<div class="hour-block" :id="'hour-' + hour" :data-hour="hour" :style="getBackgroundStyle(hour)"
|
||||
:class="{'selected': isSelected(hour)}" @mousedown="startDrag($event, hour)"
|
||||
@mouseover="dragSelect(hour)">
|
||||
<div><strong x-text="formatHour(hour)"></strong></div>
|
||||
<div class="weight"><span x-text="schedule[hour]"></span></div>
|
||||
<div class="papers">
|
||||
<span x-text="getPapersPerHour(hour)"></span> p.
|
||||
</div>
|
||||
<input type="hidden" :name="'hour_' + hour" :value="schedule[hour]" />
|
||||
<!-- Volume and Schedule Controls -->
|
||||
<div class="row g-3 mb-3">
|
||||
<!-- Daily Volume Column -->
|
||||
<div class="col-md-4" x-data="{ volumeValue: volume }">
|
||||
<div class="card h-100">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0"><i class="fas fa-chart-line"></i> Daily Volume</h5>
|
||||
</div>
|
||||
</template>
|
||||
<div class="card-body">
|
||||
<p class="lead mb-2">
|
||||
<strong x-text="volume"></strong> papers/day
|
||||
</p>
|
||||
<div class="input-group input-group-sm mb-2">
|
||||
<input type="number" class="form-control" x-model="volumeValue" min="1"
|
||||
max="{{ max_volume }}" required />
|
||||
<button type="button" class="btn btn-primary" @click="updateVolume()">
|
||||
<i class="fas fa-save"></i> Update
|
||||
</button>
|
||||
</div>
|
||||
<small class="text-muted">Range: 1-{{ max_volume }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-group mb-4 w-50">
|
||||
<label class="input-group-text">Set Weight:</label>
|
||||
<input type="number" step="0.1" min="0" max="5" x-model="newWeight" class="form-control" />
|
||||
<button type="button" class="btn btn-outline-primary" @click="applyWeight()">
|
||||
Apply to Selected
|
||||
</button>
|
||||
<!-- Legend Column -->
|
||||
<div class="col-md-8">
|
||||
<div class="card h-100">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0"><i class="fas fa-info-circle"></i> Quick Guide</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center justify-content-between mb-2">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="weight-gradient me-2"></div>
|
||||
<small>Darker blocks = higher weight</small>
|
||||
</div>
|
||||
<div class="badge bg-info">Formula: (Weight ÷ Total) × Volume</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center small text-muted">
|
||||
<div class="me-3"><i class="fas fa-mouse-pointer"></i> Click to select hours</div>
|
||||
<div class="me-3"><i class="fas fa-arrows-alt-h"></i> Drag to select multiple</div>
|
||||
<div><i class="fas fa-save"></i> Save after changes</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="{{ url_for('config.general') }}" class="btn btn-outline-secondary">⬅ Back</a>
|
||||
<button type="button" class="btn btn-success" @click="saveSchedule()">💾 Save Schedule</button>
|
||||
<!-- 24-Hour Schedule -->
|
||||
<form id="scheduleForm">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center bg-light">
|
||||
<h5 class="mb-0"><i class="fas fa-clock"></i> 24-Hour Schedule</h5>
|
||||
<span class="badge bg-info"
|
||||
x-text="selectedHours.length ? selectedHours.length + ' hours selected' : ''"></span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="timeline mb-3" @mouseup="endDrag()" @mouseleave="endDrag()">
|
||||
<template x-for="hour in Object.keys(schedule)" :key="hour">
|
||||
<div class="hour-block" :id="'hour-' + hour" :data-hour="hour"
|
||||
:style="getBackgroundStyle(hour)" :class="{'selected': isSelected(hour)}"
|
||||
@mousedown="startDrag($event, hour)" @mouseover="dragSelect(hour)">
|
||||
<div><strong x-text="formatHour(hour)"></strong></div>
|
||||
<div class="weight"><span x-text="schedule[hour]"></span></div>
|
||||
<div class="papers">
|
||||
<span x-text="getPapersPerHour(hour)"></span> p.
|
||||
</div>
|
||||
<input type="hidden" :name="'hour_' + hour" :value="schedule[hour]" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="input-group mb-2">
|
||||
<label class="input-group-text"><i class="fas fa-weight"></i> Weight</label>
|
||||
<input type="number" step="0.1" min="0.1" max="5" x-model="newWeight"
|
||||
class="form-control" />
|
||||
<button type="button" class="btn btn-primary" @click="applyWeight()"
|
||||
:disabled="selectedHours.length === 0">
|
||||
Apply to <span x-text="selectedHours.length"></span> Selected
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="{{ url_for('config.general') }}" class="btn btn-outline-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Back
|
||||
</a>
|
||||
<button type="button" class="btn btn-success" @click="saveSchedule()">
|
||||
<i class="fas fa-save"></i> Save Schedule
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -16,6 +16,12 @@
|
||||
<label>Status</label>
|
||||
<select name="status" class="form-select">
|
||||
<option value="">All</option>
|
||||
{% if request.args.get('status') == 'New' %}
|
||||
<option value="New" selected>New</option>
|
||||
{% else %}
|
||||
<option value="New">New</option>
|
||||
{% endif %}
|
||||
|
||||
{% if request.args.get('status') == 'Pending' %}
|
||||
<option value="Pending" selected>Pending</option>
|
||||
{% else %}
|
||||
|
Loading…
x
Reference in New Issue
Block a user