Skip to content
Open
Show file tree
Hide file tree
Changes from 134 commits
Commits
Show all changes
135 commits
Select commit Hold shift + click to select a range
e61e9a6
Fix:Expose general collection prefs for picklist scoping and attachme…
Gitesh307 Oct 1, 2025
87c5e32
implement Collection Preferences UI with dedicated definitions
Gitesh307 Oct 2, 2025
f8c579a
adding missing files for the Collection preferences
Gitesh307 Oct 2, 2025
ff7788d
resolve typecheck errors in Collection Preferences definitions
Gitesh307 Oct 3, 2025
44b1da0
add Collection Preferences UI and editor with doc links
Gitesh307 Oct 4, 2025
e70f796
implify CollectionPreferences page by removing internal save
Gitesh307 Oct 4, 2025
ce59d26
Corrected specifyNetwork keys to publishingOrg and datasetKey
Gitesh307 Oct 4, 2025
70ea534
fix TypeScript errors in collection preference definitions
Gitesh307 Oct 4, 2025
751fcc5
align CollectionDefinitions with UserDefinitions typing
Gitesh307 Oct 4, 2025
20b207e
Fix localization scanner issues in preferences
Gitesh307 Oct 4, 2025
5e1ab01
Lint code with ESLint and Prettier
Gitesh307 Oct 4, 2025
91644ab
adding path for role gated access
Gitesh307 Oct 5, 2025
454e758
Merge branch 'issue-7440' of https://github.com/specify/specify7 into…
Gitesh307 Oct 6, 2025
78c6e54
Refactor collection preferences renderer and documentation link layout
Gitesh307 Oct 6, 2025
f6c0493
Lint code with ESLint and Prettier
Gitesh307 Oct 6, 2025
c4ddea8
Localization cleanup for collection preferences
Gitesh307 Oct 6, 2025
5a61689
Lint code with ESLint and Prettier
Gitesh307 Oct 6, 2025
9b48971
removed collection pref refrence from User Tools
Gitesh307 Oct 6, 2025
d662587
remove extra language lines and keep only 'en-us'
Gitesh307 Oct 7, 2025
ad70ddc
extract shared logic into createPreferencesEditor and wire User/Colle…
Gitesh307 Oct 7, 2025
8d33e36
Lint code with ESLint and Prettier
Gitesh307 Oct 7, 2025
3de5eca
implemented IR<T> for preferences typing
Gitesh307 Oct 7, 2025
7f6782d
Merge branch 'issue-7440' of https://github.com/specify/specify7 into…
Gitesh307 Oct 7, 2025
e58d9f0
resolve BasePreferences context type incompatibility in index.tsx
Gitesh307 Oct 7, 2025
40479b2
Lint code with ESLint and Prettier
Gitesh307 Oct 7, 2025
58e01a6
simplify resolveCollectionDocumentHref logic using unified NAME_DOCS_MAP
Gitesh307 Oct 7, 2025
ff875da
Merge branch 'issue-7440' of https://github.com/specify/specify7 into…
Gitesh307 Oct 7, 2025
613d31c
Lint code with ESLint and Prettier
Gitesh307 Oct 7, 2025
81ca7e4
unify visibilityContext to remove duplication
Gitesh307 Oct 7, 2025
b879af0
Merge branch 'issue-7440' of https://github.com/specify/specify7 into…
Gitesh307 Oct 7, 2025
728bfed
optimize preferences wrappers by introducing FetchGate component.
Gitesh307 Oct 7, 2025
3b58630
simplify className logic for documentation paragraph
Gitesh307 Oct 7, 2025
e24a4fb
Localization cleanup for collection preferences
Gitesh307 Oct 8, 2025
444d3bf
removed `as unknown` casts
Gitesh307 Oct 8, 2025
ee4eb3b
consolidate doc links and merge catalog-number card
Gitesh307 Oct 10, 2025
41c8539
removed unused imports
Gitesh307 Oct 10, 2025
c69f079
function call
Gitesh307 Oct 10, 2025
3d1b40c
Lint code with ESLint and Prettier
Gitesh307 Oct 10, 2025
f91ea9a
render editor inline for User tools menu
Gitesh307 Oct 11, 2025
04c1788
Merge branch 'issue-7440' of https://github.com/specify/specify7 into…
Gitesh307 Oct 11, 2025
17b28db
Lint code with ESLint and Prettier
Gitesh307 Oct 11, 2025
f1eddb7
Feat: Refactor and add UI to control Global preferences
Gitesh307 Oct 12, 2025
549792e
Editor Configuration for Global Pref
Gitesh307 Oct 12, 2025
2b198a5
Global pref app resources integration
Gitesh307 Oct 12, 2025
24e6638
localization strings
Gitesh307 Oct 12, 2025
684b974
Global Preferences View, Routing and User tools menu logic
Gitesh307 Oct 12, 2025
10073ac
Add remotePreferences test coverage and stabilize ajax mocks
Gitesh307 Oct 12, 2025
e24fc51
ix test-mode ajax mock import without bundling node modules
Gitesh307 Oct 12, 2025
be2f364
removed extra localization text
Gitesh307 Oct 12, 2025
307590f
removed redundant localization strings
Gitesh307 Oct 12, 2025
bb4ec4e
added the import statement
Gitesh307 Oct 12, 2025
c6918af
Enable Global Preferences visual editor for legacy resources
Gitesh307 Oct 13, 2025
a75145c
Fix Global Preferences tests and harden ajax mock
Gitesh307 Oct 13, 2025
94e4c90
Stabilize AppResources tests for Global Preferences rename
Gitesh307 Oct 13, 2025
fccbefe
declare explicit return type for flattenResources
Gitesh307 Oct 13, 2025
4852be1
update AppResourcesTab and useResourcesTree test cases for Global Pre…
Gitesh307 Oct 13, 2025
a0f9489
remove unused container variable in AppResourcesTab.test.tsx
Gitesh307 Oct 13, 2025
3f7f9c3
Lint code with ESLint and Prettier
Gitesh307 Oct 13, 2025
f17e059
restrict Global Preferences visual editor to 'Global Prefs' directory…
Gitesh307 Oct 13, 2025
092db6d
Merge branch 'issue-7442-3' of https://github.com/specify/specify7 in…
Gitesh307 Oct 13, 2025
58335eb
Fix Global Preferences date dropdowns in visual editor
Gitesh307 Oct 13, 2025
e223eff
added localized helper to wrap the raw string in the LocalizedString …
Gitesh307 Oct 13, 2025
0f61df1
Lint code with ESLint and Prettier
Gitesh307 Oct 13, 2025
30427ab
Modularize preferences localization into smaller files
Gitesh307 Oct 16, 2025
1c7454a
createDictionary export for modularize prefrences
Gitesh307 Oct 17, 2025
ab64e70
Refactor preference localization dictionaries to expose raw maps
Gitesh307 Oct 17, 2025
c6a0b1d
fix: links to docs
grantfitzsimmons Oct 17, 2025
574acf8
Modularize preferences localization dictionary
Gitesh307 Oct 17, 2025
b1b0339
Merge branch 'issue-7440' of https://github.com/specify/specify7 into…
Gitesh307 Oct 17, 2025
7d78c52
Lint code with ESLint and Prettier
Gitesh307 Oct 17, 2025
9c4bc18
refactor(preferences): improve tree management
grantfitzsimmons Oct 17, 2025
2d5870c
fix: improve public attachment description
grantfitzsimmons Oct 17, 2025
8414c82
Update attachments.ts
grantfitzsimmons Oct 17, 2025
69986f5
feat: add descriptions for specify network fields
grantfitzsimmons Oct 17, 2025
94d499a
feat: improve descriptions for stats fields
grantfitzsimmons Oct 17, 2025
0e9f9c2
feat: improve title for synonym behavior section
grantfitzsimmons Oct 17, 2025
a9133aa
feat: improve cat number inheritance
grantfitzsimmons Oct 17, 2025
2ca038b
feat: improve descriptions for catalog number inheritance
grantfitzsimmons Oct 17, 2025
f2c4c2b
feat: add better icon, distinguish preferences
grantfitzsimmons Oct 17, 2025
c08bc13
fix: reorder trees in order of relevance
grantfitzsimmons Oct 17, 2025
fc6616f
feat(collection preferences): add sidebar
grantfitzsimmons Oct 17, 2025
8f9682f
feat(preferences): match user preferences visual
grantfitzsimmons Oct 17, 2025
9c20d17
Merge branch 'main' into issue-7440
grantfitzsimmons Oct 18, 2025
da3407e
fix: failing test
grantfitzsimmons Oct 18, 2025
84720f7
fix: remove unused localization strings
grantfitzsimmons Oct 18, 2025
a0e5463
refactor: simplify code
grantfitzsimmons Oct 18, 2025
7a18d71
Lint code with ESLint and Prettier
grantfitzsimmons Oct 18, 2025
93e824b
Merge branch 'issue-7440' into issue-7442-3
grantfitzsimmons Oct 18, 2025
d55c3cb
fix: add missing localization strings
grantfitzsimmons Oct 18, 2025
1fac628
feat(preferences): match collection preferences visual
grantfitzsimmons Oct 18, 2025
914d391
fix: add static test globalpreferences
grantfitzsimmons Oct 18, 2025
747f726
Lint code with ESLint and Prettier
grantfitzsimmons Oct 18, 2025
98f7152
feat: organize global settings into categories
grantfitzsimmons Oct 18, 2025
62eaab8
Merge branch 'issue-7442-3' of https://github.com/specify/specify7 in…
grantfitzsimmons Oct 18, 2025
2b35679
fix: failing test
grantfitzsimmons Oct 18, 2025
5cc8078
fixing failing tests
Gitesh307 Oct 20, 2025
8f7c0ae
Migrate screen date format from remote prefs into GlobalPreferences
Gitesh307 Oct 20, 2025
4d49db9
resolve readonly assignment errors in global preferences utils and lo…
Gitesh307 Oct 20, 2025
aa5e251
Lint code with ESLint and Prettier
Gitesh307 Oct 20, 2025
86910b6
ensure Global Preferences read/write the global app resource
Gitesh307 Oct 31, 2025
a70172a
satisfy TS readonly types in global preferences flow
Gitesh307 Oct 31, 2025
d710796
align tests with normalized formats and mock headers
Gitesh307 Oct 31, 2025
fa32925
Lint code with ESLint and Prettier
Gitesh307 Oct 31, 2025
fbf89eb
Merge branch 'issue-7440' into issue-7442-3
Gitesh307 Nov 2, 2025
4598929
Fix remote pref definitions regression
Gitesh307 Nov 2, 2025
21fdc3f
Fix collection pref usage and clean duplicate localization keys
Gitesh307 Nov 2, 2025
1a9946b
resolved merge conflicts
Gitesh307 Nov 3, 2025
03b82ff
Lint code with ESLint and Prettier
Gitesh307 Nov 3, 2025
860f25b
Merge branch 'issue-7440' into issue-7442-3
Gitesh307 Nov 16, 2025
969eceb
Lint code with ESLint and Prettier
Gitesh307 Nov 16, 2025
93290fe
Merge remote-tracking branch 'origin/issue-7440' into issue-7442-3
Gitesh307 Nov 16, 2025
88a5a21
Restrict global pref accessibilty to authorised roles
Gitesh307 Nov 16, 2025
6e0489b
Lint code with ESLint and Prettier
Gitesh307 Nov 16, 2025
3da7ccb
Restore GlobalPreferences fetch to cache-buster list
Gitesh307 Nov 17, 2025
e6687cd
Handle undefined admin flag when filtering global preferences
Gitesh307 Nov 17, 2025
b60ec83
Lint code with ESLint and Prettier
Gitesh307 Nov 17, 2025
605aebb
Merge branch 'issue-7440' into issue-7442-3
Gitesh307 Nov 18, 2025
edf09ca
Handle undefined admin flag when filtering global preferences
Gitesh307 Nov 18, 2025
97ca50c
Lint code with ESLint and Prettier
Gitesh307 Nov 18, 2025
c102f78
Merge branch 'issue-7440' into issue-7442-3
Gitesh307 Nov 18, 2025
9694d44
Fix global prefs visibility when isadmin is undefined
Gitesh307 Nov 18, 2025
7518cf0
Lint code with ESLint and Prettier
Gitesh307 Nov 18, 2025
ab0ea15
gate stats fetch by rank preference
Gitesh307 Nov 18, 2025
6dabaa3
Lint code with ESLint and Prettier
Gitesh307 Nov 18, 2025
29990fc
removed stats fetch by rank pref logic
Gitesh307 Nov 18, 2025
bec19a6
Fix audit log preference handling and add tests for toggle
Gitesh307 Nov 19, 2025
03de6eb
statsThreshold logic correction and auditlog tests
Gitesh307 Nov 19, 2025
4083942
Respect global attachment thumbnail preference across attachment views
Gitesh307 Nov 19, 2025
b86c71e
Lint code with ESLint and Prettier
Gitesh307 Nov 19, 2025
19353ca
Drop obsolete entries from remote prefs which is now handled by Globa…
Gitesh307 Nov 20, 2025
c8594cb
Sync Global Preferences between user tools and App Resources
Gitesh307 Nov 20, 2025
17ccc8f
Lint code with ESLint and Prettier
Gitesh307 Nov 20, 2025
4a13cef
resolved multiobject returned error for sync global prefs
Gitesh307 Nov 20, 2025
b8a2c21
Add shared notifier for global preference json and UI sync
Gitesh307 Nov 20, 2025
05e2e9b
Revise .env file with database user details
Gitesh307 Nov 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 6 additions & 28 deletions .env
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should merge these env file changes into main. The database user values need to be available to users to edit for their deployment. If users want to use the root/master user to the migrations, then they'll need to set the migrator_name to root.

Also, we should probably keep those other parameters set, like the redis values.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be resolved. 👍

Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,22 @@ DATABASE_PORT=3306
MYSQL_ROOT_PASSWORD=password
DATABASE_NAME=specify

# The following are database users with specific roles and privileges.
# If the migrator and app user are not defined, the system will use the master user credentials.
# See documenation https://discourse.specifysoftware.org/t/new-blank-database-creation-database-user-levels/3023

# MASTER Database User
# Full database administrator, used for initial setup and migrations requiring elevated privileges.
# When running Specify 7 for the first time or during updates that
# require migrations, ensure that the MASTER_NAME and MASTER_PASSWORD
# are set to the root username and password. This will ensure proper
# execution of Django migrations during the initial setup.
# After launching Specify and verifying the update is complete, you can
# safely replace these credentials with the master SQL user name and password.
MASTER_NAME=root
MASTER_PASSWORD=password

# MIGRATOR Database User
# User with elevated privileges to perform migrations (create/drop/modify tables, etc.), for Django migration steps.
MIGRATOR_NAME=specify_migrator
MIGRATOR_PASSWORD=specify_migrator

# APP Database User
# Normal runtime database user that performs application-level operations.
APP_USER_NAME=specify_user
APP_USER_PASSWORD=specify_user

# Enabling this option allows administrators with access to the
# backend Specify instance to log in as any user for support
# purposes without knowing their password.
# https://discourse.specifysoftware.org/t/allow-support-login-documentation/2838
ALLOW_SUPPORT_LOGIN=false
# The amount of time in seconds each token is valid for
SUPPORT_LOGIN_TTL = 180

# Make sure to set the `SECRET_KEY` to a unique value
SECRET_KEY=change_this_to_some_unique_random_string

ASSET_SERVER_URL=http://host.docker.internal/web_asset_store.xml
# Make sure to set the `ASSET_SERVER_KEY` to a unique value
ASSET_SERVER_KEY=your_asset_server_access_key

REDIS_HOST=redis
REDIS_PORT=6379
REDIS_DB_INDEX=0

REPORT_RUNNER_HOST=report-runner
REPORT_RUNNER_PORT=8080

Expand Down
7 changes: 6 additions & 1 deletion specifyweb/backend/context/remote_prefs.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ def get_remote_prefs() -> str:

def get_global_prefs() -> str:
res = Spappresourcedata.objects.filter(
spappresource__name='GlobalPreferences')
if res.exists():
return '\n'.join(force_str(r.data) for r in res)

legacy_res = Spappresourcedata.objects.filter(
spappresource__name='preferences',
spappresource__spappresourcedir__usertype='Global Prefs')
return '\n'.join(force_str(r.data) for r in res)
return '\n'.join(force_str(r.data) for r in legacy_res)
1 change: 1 addition & 0 deletions specifyweb/backend/context/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
re_path(r'^app.resource$', views.app_resource),
re_path(r'^available_related_searches.json$', views.available_related_searches),
re_path(r'^remoteprefs.properties$', views.remote_prefs),
path('global-preferences-resource/', views.global_preferences_resource),

re_path(r'^attachment_settings.json$', attachment_settings),
re_path(r'^report_runner_status.json$', report_runner_status),
Expand Down
132 changes: 130 additions & 2 deletions specifyweb/backend/context/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,18 @@
PermissionTargetAction, \
check_permission_targets, skip_collection_access_check, query_pt, \
CollectionAccessPT
from specifyweb.specify.models import Collection, Collectionobject, Institution, \
Specifyuser, Spprincipal, Spversion, Collectionobjecttype
from specifyweb.specify.models import (
Collection,
Collectionobject,
Institution,
Specifyuser,
Spprincipal,
Spversion,
Collectionobjecttype,
Spappresource,
Spappresourcedata,
Spappresourcedir,
)
from specifyweb.specify.models_utils.schema import base_schema
from specifyweb.specify.models_utils.serialize_datamodel import datamodel_to_json
from specifyweb.specify.api.serializers import uri_for_model
Expand Down Expand Up @@ -628,13 +638,131 @@ def view_helper(request, limit):

return get_views(collection, request.specify_user, view_name, limit, table)

ALLOWED_GLOBAL_PREFERENCE_KEYS = (
'auditing.do_audits',
'auditing.audit_field_updates',
'ui.formatting.scrdateformat',
'ui.formatting.scrmonthformat',
'attachment.preview_size',
)


def filter_global_preferences_text(data: str) -> str:
result = {}
for line in data.splitlines():
if not line or line.strip().startswith('#') or '=' not in line:
continue
key, value = line.split('=', 1)
result[key.strip()] = value.strip()

filtered = [
f'{key}={result[key]}'
for key in ALLOWED_GLOBAL_PREFERENCE_KEYS
if key in result
]
return '\n'.join(filtered)


def find_preferences_resource_data(collection, discipline, usertype: str) -> str:
directory = (
Spappresourcedir.objects.filter(
collection=collection,
discipline=discipline,
ispersonal=False,
specifyuser=None,
usertype=usertype,
)
.order_by('id')
.first()
)
if directory is None:
return ''

resource = (
Spappresource.objects.filter(name='preferences', spappresourcedir=directory)
.order_by('id')
.first()
)
if resource is None:
return ''

data = (
Spappresourcedata.objects.filter(spappresource=resource)
.order_by('id')
.first()
)
return data.data if data is not None else ''

@require_http_methods(['GET', 'HEAD'])
@login_maybe_required
@cache_control(max_age=86400, private=True)
def remote_prefs(request):
"Return the 'remoteprefs' java properties file from the database."
return HttpResponse(get_remote_prefs(), content_type='text/x-java-properties')

@require_http_methods(['GET', 'PUT'])
@login_maybe_required
@cache_control(max_age=0, private=True)
def global_preferences_resource(request):
"Update the legacy 'preferences' app resource that backs the App Resources editor."
data = request.body.decode('utf-8', 'replace')
collection = request.specify_collection
discipline = collection.discipline if collection is not None else None

if request.method == 'GET':
content = find_preferences_resource_data(collection, discipline, 'Global Prefs')
if not content:
content = find_preferences_resource_data(collection, discipline, 'Prefs')
filtered = filter_global_preferences_text(content)
return HttpResponse(filtered, content_type='text/plain')

def resolve_directory(usertype: str) -> Spappresourcedir:
queryset = Spappresourcedir.objects.filter(
collection=collection,
discipline=discipline,
ispersonal=False,
specifyuser=None,
usertype=usertype,
).order_by('id')
directory = queryset.first()
if directory is not None:
return directory
return Spappresourcedir.objects.create(
collection=collection,
discipline=discipline,
ispersonal=False,
specifyuser=None,
usertype=usertype,
)

def upsert_preferences_resource(usertype: str) -> None:
directory = resolve_directory(usertype)
resource, _ = Spappresource.objects.get_or_create(
name='preferences',
spappresourcedir=directory,
defaults={
'level': 0,
'mimetype': 'text/x-java-properties',
'metadata': '',
'specifyuser': request.specify_user,
},
)
resource.mimetype = 'text/x-java-properties'
resource.metadata = ''
resource.save()

spappresourcedata, _ = Spappresourcedata.objects.get_or_create(
spappresource=resource,
defaults={'data': data},
)
spappresourcedata.data = data
spappresourcedata.save()

upsert_preferences_resource('Global Prefs')
upsert_preferences_resource('Prefs')

return HttpResponse('', content_type='text/plain', status=204)

@require_http_methods(['GET', 'HEAD'])
def get_server_time(request):
return JsonResponse({"server_time": timezone.now().isoformat()})
Expand Down
12 changes: 9 additions & 3 deletions specifyweb/backend/stored_queries/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from sqlalchemy import types

import specifyweb.backend.context.app_resource as app_resource
from specifyweb.backend.context.remote_prefs import get_remote_prefs
from specifyweb.backend.context.remote_prefs import get_global_prefs, get_remote_prefs

from specifyweb.specify.utils.agent_types import agent_types
from specifyweb.specify.models import datamodel, Splocalecontainer
Expand Down Expand Up @@ -455,8 +455,14 @@ def _fieldformat(self, table: Table, specify_field: Field,


def get_date_format() -> str:
match = re.search(r'ui\.formatting\.scrdateformat=(.+)', get_remote_prefs())
date_format = match.group(1).strip() if match is not None else 'yyyy-MM-dd'
date_format_text = 'yyyy-MM-dd'
for prefs in (get_global_prefs(), get_remote_prefs()):
match = re.search(r'ui\.formatting\.scrdateformat=(.+)', prefs)
if match is not None:
date_format_text = match.group(1).strip()
break

date_format = date_format_text
mysql_date_format = LDLM_TO_MYSQL.get(date_format, "%Y-%m-%d")
logger.debug("dateformat = %s = %s", date_format, mysql_date_format)
return mysql_date_format
Expand Down
44 changes: 33 additions & 11 deletions specifyweb/backend/workbench/upload/auditlog.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,35 @@

from . import auditcodes


def _extract_pref_bool(pref_text: str | None, pref_key: str) -> bool | None:
"""
Try to extract a boolean preference value from a preference file.
Returns None if the key is not present or the value is not boolean-like.
"""
if not pref_text:
return None
match = re.search(rf'^{re.escape(pref_key)}\s*=\s*(.+)$', pref_text, re.MULTILINE)
if match:
value = match.group(1).strip().lower()
if value == 'true':
return True
if value == 'false':
return False
return None

def _get_pref_bool(pref_key: str, default: bool = False) -> bool:
"""
Return the preference value for the given key, preferring the new
GlobalPreferences resource and falling back to the legacy remote
preferences. When missing, default to the provided value.
"""
for source in (get_global_prefs, get_remote_prefs):
value = _extract_pref_bool(source(), pref_key)
if value is not None:
return value
return default

def str_to_bytes(string: str, max_length: int) -> bytes:
str_as_bytes = string.encode()
return str_as_bytes[:max_length]
Expand All @@ -42,7 +71,8 @@ class AuditLog:
_auditingFlds = None
_auditing = None
_lastCheck = None
_checkInterval = 900
# Re-check preferences frequently so UI changes (enable/disable) take effect quickly
_checkInterval = 5

def isAuditingFlds(self):
return self.isAuditing() and self._auditingFlds
Expand All @@ -51,16 +81,8 @@ def isAuditing(self):
if settings.DISABLE_AUDITING:
return False
if self._auditing is None or self._lastCheck is None or time() - self._lastCheck > self._checkInterval:
match = re.search(r'auditing\.do_audits=(.+)', get_remote_prefs())
if match is None:
self._auditing = True
else:
self._auditing = False if match.group(1).lower() == 'false' else True
match = re.search(r'auditing\.audit_field_updates=(.+)', get_remote_prefs())
if match is None:
self._auditingFlds = True
else:
self._auditingFlds = False if match.group(1).lower() == 'false' else True
self._auditing = _get_pref_bool('auditing.do_audits', default=True)
self._auditingFlds = _get_pref_bool('auditing.audit_field_updates', default=True)
self.purge()
self._lastCheck = time()
return self._auditing;
Expand Down
32 changes: 32 additions & 0 deletions specifyweb/backend/workbench/upload/test_auditlog_prefs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from django.test import SimpleTestCase
from unittest.mock import patch

from specifyweb.backend.workbench.upload.auditlog import _extract_pref_bool, _get_pref_bool


class AuditLogPreferenceTests(SimpleTestCase):
def test_extract_pref_bool_parses_true_false(self) -> None:
self.assertTrue(_extract_pref_bool("auditing.do_audits=true", "auditing.do_audits"))
self.assertFalse(_extract_pref_bool("auditing.do_audits=false", "auditing.do_audits"))
self.assertIsNone(_extract_pref_bool("auditing.do_audits=maybe", "auditing.do_audits"))
self.assertIsNone(_extract_pref_bool("", "auditing.do_audits"))

@patch('specifyweb.backend.workbench.upload.auditlog.get_global_prefs', return_value="auditing.do_audits=false")
@patch('specifyweb.backend.workbench.upload.auditlog.get_remote_prefs', return_value="auditing.do_audits=true")
def test_prefers_global_preferences_when_present(self, _mock_remote, _mock_global) -> None:
self.assertFalse(_get_pref_bool("auditing.do_audits"))

@patch('specifyweb.backend.workbench.upload.auditlog.get_global_prefs', return_value="")
@patch('specifyweb.backend.workbench.upload.auditlog.get_remote_prefs', return_value="auditing.audit_field_updates=false")
def test_uses_remote_when_global_missing(self, _mock_remote, _mock_global) -> None:
self.assertFalse(_get_pref_bool("auditing.audit_field_updates"))

@patch('specifyweb.backend.workbench.upload.auditlog.get_global_prefs', return_value="")
@patch('specifyweb.backend.workbench.upload.auditlog.get_remote_prefs', return_value="")
def test_default_false_when_missing_everywhere(self, _mock_remote, _mock_global) -> None:
self.assertFalse(_get_pref_bool("auditing.do_audits"))

@patch('specifyweb.backend.workbench.upload.auditlog.get_global_prefs', return_value="")
@patch('specifyweb.backend.workbench.upload.auditlog.get_remote_prefs', return_value="")
def test_default_value_used_when_requested(self, _mock_remote, _mock_global) -> None:
self.assertTrue(_get_pref_bool("auditing.do_audits", default=True))
Loading