[FIX] HORILLA_VIEWS: Generic import issue fix
This commit is contained in:
@@ -4,7 +4,7 @@ employee/sidebar.py
|
||||
To set Horilla sidebar for employee
|
||||
"""
|
||||
|
||||
from django.urls import reverse
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext_lazy as trans
|
||||
|
||||
from accessibility.methods import check_is_accessible
|
||||
@@ -19,48 +19,48 @@ IMG_SRC = "images/ui/employees.svg"
|
||||
SUBMENUS = [
|
||||
{
|
||||
"menu": trans("Profile"),
|
||||
"redirect": reverse("employee-profile"),
|
||||
"redirect": reverse_lazy("employee-profile"),
|
||||
"accessibility": "employee.sidebar.profile_accessibility",
|
||||
},
|
||||
{
|
||||
"menu": trans("Employees"),
|
||||
"redirect": reverse("employee-view"),
|
||||
"redirect": reverse_lazy("employee-view"),
|
||||
"accessibility": "employee.sidebar.employee_accessibility",
|
||||
},
|
||||
{
|
||||
"menu": trans("Document Requests"),
|
||||
"redirect": reverse("document-request-view"),
|
||||
"redirect": reverse_lazy("document-request-view"),
|
||||
"accessibility": "employee.sidebar.document_accessibility",
|
||||
},
|
||||
{
|
||||
"menu": trans("Shift Requests"),
|
||||
"redirect": reverse("shift-request-view"),
|
||||
"redirect": reverse_lazy("shift-request-view"),
|
||||
},
|
||||
{
|
||||
"menu": trans("Work Type Requests"),
|
||||
"redirect": reverse("work-type-request-view"),
|
||||
"redirect": reverse_lazy("work-type-request-view"),
|
||||
},
|
||||
{
|
||||
"menu": trans("Rotating Shift Assign"),
|
||||
"redirect": reverse("rotating-shift-assign"),
|
||||
"redirect": reverse_lazy("rotating-shift-assign"),
|
||||
"accessibility": "employee.sidebar.rotating_shift_accessibility",
|
||||
},
|
||||
{
|
||||
"menu": trans("Rotating Work Type Assign"),
|
||||
"redirect": reverse("rotating-work-type-assign"),
|
||||
"redirect": reverse_lazy("rotating-work-type-assign"),
|
||||
"accessibility": "employee.sidebar.rotating_work_type_accessibility",
|
||||
},
|
||||
{
|
||||
"menu": trans("Disciplinary Actions"),
|
||||
"redirect": reverse("disciplinary-actions"),
|
||||
"redirect": reverse_lazy("disciplinary-actions"),
|
||||
},
|
||||
{
|
||||
"menu": trans("Policies"),
|
||||
"redirect": reverse("view-policies"),
|
||||
"redirect": reverse_lazy("view-policies"),
|
||||
},
|
||||
{
|
||||
"menu": trans("Organization Chart"),
|
||||
"redirect": reverse("organisation-chart"),
|
||||
"redirect": reverse_lazy("organisation-chart"),
|
||||
},
|
||||
]
|
||||
|
||||
@@ -75,7 +75,7 @@ def profile_accessibility(request, submenu, user_perms, *args, **kwargs):
|
||||
return accessible
|
||||
# try:
|
||||
# if accessible:
|
||||
# submenu["redirect"] = reverse("employee-profile", kwargs={"obj_id": request.user.employee_get.id})
|
||||
# submenu["redirect"] = reverse_lazy("employee-profile", kwargs={"obj_id": request.user.employee_get.id})
|
||||
# except Exception:
|
||||
# # If an exception occurs, do nothing
|
||||
# pass
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<div class="oh-profile-section__card">
|
||||
<div class="row">
|
||||
<div class="col-12">{{form.errors}}</div>
|
||||
{% for field in form.visible_fields %}
|
||||
{% for field in form.visible_fields %}
|
||||
{% if field.field.widget|is_select_multiple or field.field.widget|is_text_area %}
|
||||
<div class="flex oh-label" for="id_{{ field.name }}">
|
||||
<label
|
||||
@@ -64,12 +64,12 @@
|
||||
<div class="oh-switch" style="width: 30px">
|
||||
{{ field|add_class:"oh-switch__checkbox" }}
|
||||
</div>
|
||||
{% else %}
|
||||
{{ field|add_class:"form-control" }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ field|add_class:"form-control" }}
|
||||
{% endif %}
|
||||
{{field.errors}}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -910,7 +910,7 @@ def assign_related(
|
||||
else:
|
||||
reverse_obj_dict[field] = value
|
||||
else:
|
||||
instance = [
|
||||
instances = [
|
||||
data
|
||||
for data in pk_values_mapping[reverse_field]
|
||||
if getattr(
|
||||
@@ -919,7 +919,8 @@ def assign_related(
|
||||
record[reverse_field],
|
||||
)
|
||||
== record[reverse_field]
|
||||
][0]
|
||||
reverse_obj_dict.update({reverse_field: instance})
|
||||
|
||||
]
|
||||
if instances:
|
||||
instance = instances[0]
|
||||
reverse_obj_dict.update({reverse_field: instance})
|
||||
return reverse_obj_dict
|
||||
|
||||
@@ -373,6 +373,8 @@ class HorillaListView(ListView):
|
||||
current = record
|
||||
for part in parts[:-1]:
|
||||
current = current.setdefault(part, {})
|
||||
if isinstance(value, float) and value.is_integer():
|
||||
value = int(value)
|
||||
current[parts[-1]] = value
|
||||
serialized.append(record)
|
||||
with_ref, without_ref = split_by_import_reference(serialized)
|
||||
@@ -496,11 +498,13 @@ class HorillaListView(ListView):
|
||||
bulk_base_fk_grouping = {}
|
||||
bulk_create_reverse_related_grouping = {}
|
||||
bulk_create_base_grouping = []
|
||||
items = []
|
||||
|
||||
related_fields = list(
|
||||
self.reverse_model_relation_to_base_model.keys()
|
||||
)
|
||||
fk_fields = self.fk_o2o_field_in_base_model
|
||||
|
||||
for record in records_to_import:
|
||||
if record.get(update_reference_key):
|
||||
del record[update_reference_key]
|
||||
@@ -575,12 +579,17 @@ class HorillaListView(ListView):
|
||||
records=items,
|
||||
view=self,
|
||||
)
|
||||
|
||||
if not items:
|
||||
items = bulk_create_base_grouping
|
||||
pre_generic_import.send(
|
||||
sender=self.model,
|
||||
records=items,
|
||||
view=self,
|
||||
)
|
||||
|
||||
self.model.objects.bulk_create(bulk_create_base_grouping)
|
||||
|
||||
post_generic_import.send(
|
||||
sender=self.model,
|
||||
records=items,
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
{% load generic_template_filters i18n %}
|
||||
<style>
|
||||
.opacity-50{
|
||||
opacity: .5!important;
|
||||
}
|
||||
</style>
|
||||
{% if import_fields and import_accessibility %}
|
||||
<div id="import_{{ view_id }}" class="oh-checkpoint-badge text-warning" style="cursor: pointer;color: hsl(211.72deg 91% 60%) !important;" data-toggle="oh-modal-toggle" data-target="#importModal{{ view_id }}" onclick="
|
||||
ids = $('#{{ selected_instances_key_id }}').attr('data-ids');
|
||||
@@ -13,7 +18,7 @@
|
||||
<button class="oh-modal__close" aria-label="Close"><ion-icon name="close-outline" role="img"></ion-icon></button>
|
||||
<div class="oh-modal__dialog-body p-0 pb-4">
|
||||
<form hx-post="/{{ post_import_sheet_path }}" hx-encoding="multipart/form-data" class="oh-profile-section">
|
||||
<div class="oh-modal__dialog-body mr-5" id="uploading" style="display: none">
|
||||
<div class="oh-modal__dialog-body mr-5" id="uploading{{view_id}}" style="display: none">
|
||||
<div class="loader-container">
|
||||
<div class="loader"></div>
|
||||
<div class="loader-text">Uploading...</div>
|
||||
@@ -27,7 +32,7 @@
|
||||
<span class="oh-dropdown__import-form-title">Upload a File</span>
|
||||
<span class="oh-dropdown__import-form-text">Drag and drop files here</span>
|
||||
</label>
|
||||
<input type="file" name="file" required="" />
|
||||
<input id="resumeUpload{{ view_id }}" type="file" name="file" required="" />
|
||||
<div class="d-inline float-end">
|
||||
<a onclick="
|
||||
$('#submitGetImportSheet{{ view_id }}').click();
|
||||
@@ -52,29 +57,19 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="modal-footer d-flex flex-row-reverse">
|
||||
<input type="submit" class="oh-btn oh-btn--small oh-btn--secondary w-100 mt-3" value="Upload" />
|
||||
<input
|
||||
onclick="
|
||||
if($('#resumeUpload{{ view_id }}').val()){
|
||||
$('#uploading{{view_id}}').show();
|
||||
$(this).addClass('opacity-50');
|
||||
setTimeout(() => {
|
||||
$(this).attr('type','button');
|
||||
}, 100);
|
||||
}
|
||||
"
|
||||
type="submit" class="oh-btn oh-btn--small oh-btn--secondary w-100 mt-3" value="Upload" />
|
||||
</div>
|
||||
</form>
|
||||
<script>
|
||||
let htmxBusy = false
|
||||
|
||||
document.body.addEventListener('htmx:configRequest', function (event) {
|
||||
if (htmxBusy) {
|
||||
event.preventDefault()
|
||||
console.warn('Blocked concurrent HTMX request.')
|
||||
} else {
|
||||
htmxBusy = true
|
||||
}
|
||||
})
|
||||
|
||||
document.body.addEventListener('htmx:afterRequest', function () {
|
||||
htmxBusy = false
|
||||
})
|
||||
|
||||
document.body.addEventListener('htmx:responseError', function () {
|
||||
htmxBusy = false
|
||||
})
|
||||
</script>
|
||||
<form id="submitGetImportSheet{{ view_id }}Form" action="/{{ get_import_sheet_path }}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="text" name="selected_ids" hidden />
|
||||
|
||||
@@ -2,9 +2,10 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class PgGitBackupConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'pg_backup'
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "pg_backup"
|
||||
|
||||
def ready(self):
|
||||
from pg_backup import scheduler
|
||||
|
||||
return super().ready()
|
||||
|
||||
@@ -37,44 +37,43 @@ Backups can also be triggered manually by calling `backup_postgres()`.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import environ
|
||||
import datetime
|
||||
import subprocess
|
||||
import shutil
|
||||
import logging
|
||||
import logging.config
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import environ
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from django.conf import settings
|
||||
|
||||
# === Logging Configuration ===
|
||||
|
||||
LOGGING_CONFIG = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'formatters': {
|
||||
'standard': {
|
||||
'format': '[%(asctime)s] [%(levelname)s] %(name)s: %(message)s'
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"standard": {"format": "[%(asctime)s] [%(levelname)s] %(name)s: %(message)s"},
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "standard",
|
||||
},
|
||||
},
|
||||
'handlers': {
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
'formatter': 'standard',
|
||||
"loggers": {
|
||||
"pg_backup": {
|
||||
"handlers": ["console"],
|
||||
"level": "INFO",
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'pg_backup': {
|
||||
'handlers': ['console'],
|
||||
'level': 'INFO',
|
||||
'propagate': False,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
logging.config.dictConfig(LOGGING_CONFIG)
|
||||
logger = logging.getLogger('pg_backup')
|
||||
logger = logging.getLogger("pg_backup")
|
||||
|
||||
# === Configuration ===
|
||||
|
||||
@@ -90,7 +89,9 @@ db = settings.DATABASES["default"]
|
||||
DB_ENGINE = db["ENGINE"]
|
||||
|
||||
if "postgresql" not in DB_ENGINE:
|
||||
logger.warning("Skipping backup scheduler: not a PostgreSQL database (engine: %s)", DB_ENGINE)
|
||||
logger.warning(
|
||||
"Skipping backup scheduler: not a PostgreSQL database (engine: %s)", DB_ENGINE
|
||||
)
|
||||
else:
|
||||
DB_NAME = db["NAME"]
|
||||
DB_USER = db["USER"]
|
||||
@@ -110,13 +111,18 @@ else:
|
||||
|
||||
command = [
|
||||
shutil.which("pg_dump"),
|
||||
"-h", DB_HOST,
|
||||
"-p", DB_PORT,
|
||||
"-U", DB_USER,
|
||||
"-F", "c",
|
||||
"-h",
|
||||
DB_HOST,
|
||||
"-p",
|
||||
DB_PORT,
|
||||
"-U",
|
||||
DB_USER,
|
||||
"-F",
|
||||
"c",
|
||||
"-b",
|
||||
"-v",
|
||||
"-f", str(backup_file),
|
||||
"-f",
|
||||
str(backup_file),
|
||||
DB_NAME,
|
||||
]
|
||||
|
||||
@@ -145,11 +151,11 @@ else:
|
||||
hour, minute = map(int, time_str.split(":"))
|
||||
scheduler.add_job(
|
||||
backup_postgres,
|
||||
'cron',
|
||||
"cron",
|
||||
hour=hour,
|
||||
minute=minute,
|
||||
id=f"backup_{hour}_{minute}",
|
||||
replace_existing=True
|
||||
replace_existing=True,
|
||||
)
|
||||
logger.info("Backup scheduled at %02d:%02d", hour, minute)
|
||||
except ValueError:
|
||||
|
||||
Reference in New Issue
Block a user