Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove global state #1141

Merged
merged 91 commits into from
Dec 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
cfdb9d5
Create basic misago.cache application
rafalp Nov 25, 2018
4c24641
Another iteration on utility module
rafalp Nov 25, 2018
50f918e
Add more features to misago.cache
rafalp Nov 25, 2018
c919604
Add tests for misago.cache.cache
rafalp Nov 27, 2018
e822611
Add tests for invalidating caches
rafalp Nov 27, 2018
38325a7
Add middleware tests
rafalp Nov 27, 2018
7d6fe8e
Small polishing on middleware tests
rafalp Nov 27, 2018
27f5058
Add tests for management command
rafalp Nov 27, 2018
6f29825
Rename misago.cache.cache to misago.cache.versions
rafalp Nov 28, 2018
2e7d18a
Merge pull request #1139 from rafalp/extract-cache-to-app
rafalp Nov 28, 2018
8762f23
Revert old cache versioning migrations to make build pass
rafalp Dec 1, 2018
f96aea9
Cleanup migration
rafalp Dec 1, 2018
b950fc4
Move user online utils to take request instead of viewer
rafalp Dec 1, 2018
cdea0c5
Remove global state from bans
rafalp Dec 1, 2018
e44ca3f
Remove bans cache versioning from old cache versioning feature
rafalp Dec 1, 2018
44b648e
Merge pull request #1143 from rafalp/remove-global-state-from-users-bans
rafalp Dec 1, 2018
58cbc43
Add non-global acl implementation and testing utils
rafalp Dec 9, 2018
8ef7c58
Include user staff and superuser status flags in user_acl
rafalp Dec 9, 2018
1e2df6e
Make tests pass for misago.users
rafalp Dec 9, 2018
0354f43
Improve get_user_status tests
rafalp Dec 9, 2018
8e63ac7
Improve patch_user_acl testing utility and get_user_status tests
rafalp Dec 9, 2018
55156a8
Improve test util to work as decorator or context processor
rafalp Dec 9, 2018
263dff9
Update misago.users tests to use new testing utilities
rafalp Dec 9, 2018
cc47a3b
Update readtracker to use user_acl
rafalp Dec 9, 2018
aebcf97
Remove cache and global state dependency from readtracker tests
rafalp Dec 9, 2018
d2be86e
Fix tests for thread view
rafalp Dec 9, 2018
0115195
Move more tests to patch_user_acl
rafalp Dec 9, 2018
7a38bd6
Make misago.categories tests pass
rafalp Dec 10, 2018
7e79a26
Redo patch_user_acl test util
rafalp Dec 11, 2018
95f9ff5
Make threads patch api tests pass
rafalp Dec 11, 2018
37bf66b
Enable stacking patch_user_acl helper
rafalp Dec 12, 2018
4ba48a7
Make tests pass for thread and post patch api, redo thread_move test …
rafalp Dec 12, 2018
bd18790
Remove unnecessary extra model refreshing logic
rafalp Dec 12, 2018
4307c0a
Fix tests for threads editor api
rafalp Dec 12, 2018
a818432
Make override_acl function raise error on use
rafalp Dec 13, 2018
bf157d8
Tweak test util and fix regressions in misago.users.tests
rafalp Dec 13, 2018
56cc7c6
Fix misago.search tests
rafalp Dec 15, 2018
19d77ea
Fix merging threads
rafalp Dec 15, 2018
5b48ed6
Make tests for thread start/reply/edit reply pass
rafalp Dec 15, 2018
e7cd7e1
Fix threads api tests
rafalp Dec 15, 2018
637ec70
Fix threads splitting
rafalp Dec 15, 2018
35a80d0
Fix bulk post delete
rafalp Dec 15, 2018
b3dd25a
Fix post merge api
rafalp Dec 15, 2018
489741b
Fix post deletion
rafalp Dec 15, 2018
2f0befd
Fix posts moving
rafalp Dec 15, 2018
e353027
Fix attachments api tests
rafalp Dec 15, 2018
a0bd67c
Fix attachments
rafalp Dec 15, 2018
26cc404
Replace RequestMock with unittest.mocks.Mock
rafalp Dec 15, 2018
5750abf
Fix bulk threads delete tests
rafalp Dec 15, 2018
0d79134
Fix private threads to work with new acl
rafalp Dec 15, 2018
b489fdb
Fix remaining posting middlewares
rafalp Dec 15, 2018
4a75270
Remove override_acl from remaining tests
rafalp Dec 15, 2018
14ddb2f
Make tests pass
rafalp Dec 15, 2018
35bee7a
Cleanup misago.acl a little
rafalp Dec 16, 2018
3a907dd
Remove User.acl_cache, User.acl_ and direct imports from misago.acl
rafalp Dec 17, 2018
593a0fd
Fix allow_lift_ban permission
rafalp Dec 17, 2018
e912a78
Add assertion for testing if cache is invalidated
rafalp Dec 17, 2018
27ed8cd
Add assertions that ACL cache is invalidated
rafalp Dec 17, 2018
d52d2da
Fix assertion error message
rafalp Dec 18, 2018
3e45c7c
Small name change
rafalp Dec 18, 2018
f5a2d60
Clean the test
rafalp Dec 18, 2018
210d552
Small change of misago.acl.cache api
rafalp Dec 18, 2018
8eff6f4
Fix build
rafalp Dec 18, 2018
7f1ee27
Merge pull request #1145 from rafalp/remove-global-state-from-acl
rafalp Dec 18, 2018
4d63810
Early groundwork for new database settings proxy
rafalp Dec 2, 2018
008a41a
Add override_dynamic_settings testing utility
rafalp Dec 2, 2018
e853de8
Add tests for getting/overriding dynamic setting value
rafalp Dec 2, 2018
8505aef
Add tests for dynamic settings loading, improve test assertions in mi…
rafalp Dec 2, 2018
8c40166
Rename tests suite, add tests for other use-cases
rafalp Dec 2, 2018
e7bb86b
Add tests for dynamic settings middleware
rafalp Dec 2, 2018
daf2130
Move context processor to request.settings, rename it to conf.
rafalp Dec 3, 2018
53e2e1d
Add dynamic settings to email context
rafalp Dec 3, 2018
ffe17db
Small code cleanups before removing global state from create_user
rafalp Dec 6, 2018
2a70559
Small cleanup for user model/manager, add util for setting up new use…
rafalp Dec 7, 2018
facfb05
Update misago.users.tests to crash less
rafalp Dec 8, 2018
6359d07
Fix misago.users tests
rafalp Dec 18, 2018
09e578b
Fix misago.core tests
rafalp Dec 18, 2018
0a7ebe4
Fix misago.threads tests
rafalp Dec 18, 2018
7c1f51e
Add StaticSettings object
rafalp Dec 20, 2018
c7ff046
Finalize misago.conf module
rafalp Dec 20, 2018
259821c
Remove special check for dynamic setting access from StaticSettings
rafalp Dec 20, 2018
6613de5
Remove db_settings usage from misago.users
rafalp Dec 20, 2018
9d18591
Remove global db_settings form codebase
rafalp Dec 20, 2018
57a0194
Revert change in user profile
rafalp Dec 20, 2018
9ecf2bd
Merge pull request #1144 from rafalp/remove-global-state-from-db-sett…
rafalp Dec 20, 2018
add80c2
Make misago.core.threadstore methods raise NotImplementedError on use
rafalp Dec 20, 2018
0207c78
Remove threadstate middleware and MisagoTestCase
rafalp Dec 20, 2018
1e22a23
Make tests pass
rafalp Dec 20, 2018
172285e
Remove misago.core.threadstore
rafalp Dec 20, 2018
4477bb0
Remove unused get_cache_key from dynamicsettings
rafalp Dec 20, 2018
fa50746
Merge pull request #1149 from rafalp/remove-global-state-threadstore
rafalp Dec 20, 2018
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
9 changes: 6 additions & 3 deletions devproject/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@
# Misago apps
'misago.admin',
'misago.acl',
'misago.cache',
'misago.core',
'misago.conf',
'misago.markup',
Expand Down Expand Up @@ -223,12 +224,14 @@
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',

'misago.cache.middleware.cache_versions_middleware',
'misago.conf.middleware.dynamic_settings_middleware',
'misago.users.middleware.UserMiddleware',
'misago.acl.middleware.user_acl_middleware',
'misago.core.middleware.ExceptionHandlerMiddleware',
'misago.users.middleware.OnlineTrackerMiddleware',
'misago.admin.middleware.AdminAuthMiddleware',
'misago.threads.middleware.UnreadThreadsCountMiddleware',
'misago.core.middleware.ThreadStoreMiddleware',
]

ROOT_URLCONF = 'devproject.urls'
Expand Down Expand Up @@ -283,12 +286,12 @@
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',

'misago.acl.context_processors.user_acl',
'misago.conf.context_processors.conf',
'misago.core.context_processors.site_address',
'misago.core.context_processors.momentjs_locale',
'misago.conf.context_processors.settings',
'misago.search.context_processors.search_providers',
'misago.users.context_processors.user_links',
'misago.legal.context_processors.legal_links',

# Data preloaders
'misago.conf.context_processors.preload_settings_json',
Expand Down
3 changes: 1 addition & 2 deletions devproject/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
# Use in-memory cache
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'uniqu3-sn0wf14k3'
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
}
}

Expand Down
4 changes: 2 additions & 2 deletions misago/acl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .api import get_user_acl, add_acl, serialize_acl

default_app_config = 'misago.acl.apps.MisagoACLsConfig'

ACL_CACHE = "acl"
65 changes: 0 additions & 65 deletions misago/acl/api.py

This file was deleted.

1 change: 1 addition & 0 deletions misago/acl/apps.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.apps import AppConfig
from .providers import providers


class MisagoACLsConfig(AppConfig):
name = 'misago.acl'
label = 'misago_acl'
Expand Down
File renamed without changes.
23 changes: 23 additions & 0 deletions misago/acl/cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from django.core.cache import cache

from misago.cache.versions import invalidate_cache

from . import ACL_CACHE


def get_acl_cache(user, cache_versions):
key = get_cache_key(user, cache_versions)
return cache.get(key)


def set_acl_cache(user, cache_versions, user_acl):
key = get_cache_key(user, cache_versions)
cache.set(key, user_acl)


def get_cache_key(user, cache_versions):
return 'acl_%s_%s' % (user.acl_key, cache_versions[ACL_CACHE])


def clear_acl_cache():
invalidate_cache(ACL_CACHE)
1 change: 0 additions & 1 deletion misago/acl/constants.py

This file was deleted.

2 changes: 2 additions & 0 deletions misago/acl/context_processors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def user_acl(request):
return {"user_acl": request.user_acl}
12 changes: 12 additions & 0 deletions misago/acl/middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django.utils.functional import SimpleLazyObject

from . import useracl


def user_acl_middleware(get_response):
"""Sets request.user_acl attribute with dict containing current user acl."""
def middleware(request):
request.user_acl = useracl.get_user_acl(request.user, request.cache_versions)
return get_response(request)

return middleware
12 changes: 2 additions & 10 deletions misago/acl/migrations/0002_acl_version_tracker.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
from django.db import migrations

from misago.acl.constants import ACL_CACHEBUSTER
from misago.core.migrationutils import cachebuster_register_cache


def register_acl_version_tracker(apps, schema_editor):
cachebuster_register_cache(apps, ACL_CACHEBUSTER)


class Migration(migrations.Migration):
"""Superseded by 0004"""

dependencies = [
('misago_acl', '0001_initial'),
('misago_core', '0001_initial'),
]

operations = [
migrations.RunPython(register_acl_version_tracker),
]
operations = []
17 changes: 17 additions & 0 deletions misago/acl/migrations/0004_cache_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
from django.db import migrations

from misago.acl import ACL_CACHE
from misago.cache.operations import StartCacheVersioning


class Migration(migrations.Migration):

dependencies = [
('misago_acl', '0003_default_roles'),
('misago_cache', '0001_initial'),
]

operations = [
StartCacheVersioning(ACL_CACHE)
]
6 changes: 3 additions & 3 deletions misago/acl/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.db import models
from django.utils.translation import gettext as _

from . import version as acl_version
from .cache import clear_acl_cache


def permissions_default():
Expand All @@ -22,11 +22,11 @@ def __str__(self):

def save(self, *args, **kwargs):
if self.pk:
acl_version.invalidate()
clear_acl_cache()
return super().save(*args, **kwargs)

def delete(self, *args, **kwargs):
acl_version.invalidate()
clear_acl_cache()
return super().delete(*args, **kwargs)


Expand Down
18 changes: 18 additions & 0 deletions misago/acl/objectacl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from .providers import providers


def add_acl_to_obj(user_acl, obj):
"""add valid ACL to obj (iterable of objects or single object)"""
if hasattr(obj, '__iter__'):
for item in obj:
_add_acl_to_obj(user_acl, item)
else:
_add_acl_to_obj(user_acl, obj)


def _add_acl_to_obj(user_acl, obj):
"""add valid ACL to single obj, helper for add_acl function"""
obj.acl = {}

for annotator in providers.get_obj_type_annotators(obj):
annotator(user_acl, obj)
2 changes: 1 addition & 1 deletion misago/acl/panels.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def process_response(self, request, response):
misago_user = None

try:
misago_acl = misago_user.acl_cache
misago_acl = request.user_acl
except AttributeError:
misago_acl = {}

Expand Down
28 changes: 15 additions & 13 deletions misago/acl/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

_NOT_INITIALIZED_ERROR = (
"PermissionProviders instance has to load providers with load() "
"before get_obj_type_annotators(), get_obj_type_serializers(), "
"before get_obj_type_annotators(), get_user_acl_serializers(), "
"list() or dict() methods will be available."
)

_ALREADY_INITIALIZED_ERROR = (
"PermissionProviders instance has already loaded providers and "
"acl_annotator or acl_serializer are no longer available."
"acl_annotator or user_acl_serializer are no longer available."
)


Expand All @@ -24,14 +24,16 @@ def __init__(self):
self._providers_dict = {}

self._annotators = {}
self._serializers = {}
self._user_acl_serializers = []

def load(self):
if not self._initialized:
self._register_providers()
self._change_lists_to_tupes(self._annotators)
self._change_lists_to_tupes(self._serializers)
self._initialized = True
if self._initialized:
raise RuntimeError("providers are already loaded")

self._register_providers()
self._coerce_dict_values_to_tuples(self._annotators)
self._user_acl_serializers = tuple(self._user_acl_serializers)
self._initialized = True

def _register_providers(self):
for namespace in settings.MISAGO_ACL_EXTENSIONS:
Expand All @@ -41,7 +43,7 @@ def _register_providers(self):
if hasattr(self._providers_dict[namespace], 'register_with'):
self._providers_dict[namespace].register_with(self)

def _change_lists_to_tupes(self, types_dict):
def _coerce_dict_values_to_tuples(self, types_dict):
for hashType in types_dict.keys():
types_dict[hashType] = tuple(types_dict[hashType])

Expand All @@ -50,18 +52,18 @@ def acl_annotator(self, hashable_type, func):
assert not self._initialized, _ALREADY_INITIALIZED_ERROR
self._annotators.setdefault(hashable_type, []).append(func)

def acl_serializer(self, hashable_type, func):
def user_acl_serializer(self, func):
"""registers ACL serializer for specified types"""
assert not self._initialized, _ALREADY_INITIALIZED_ERROR
self._serializers.setdefault(hashable_type, []).append(func)
self._user_acl_serializers.append(func)

def get_obj_type_annotators(self, obj):
assert self._initialized, _NOT_INITIALIZED_ERROR
return self._annotators.get(obj.__class__, [])

def get_obj_type_serializers(self, obj):
def get_user_acl_serializers(self):
assert self._initialized, _NOT_INITIALIZED_ERROR
return self._serializers.get(obj.__class__, [])
return self._user_acl_serializers

def list(self):
assert self._initialized, _NOT_INITIALIZED_ERROR
Expand Down
56 changes: 56 additions & 0 deletions misago/acl/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from contextlib import ContextDecorator, ExitStack, contextmanager
from functools import wraps
from unittest.mock import patch

from .useracl import get_user_acl

__all__ = ["patch_user_acl"]


class patch_user_acl(ContextDecorator, ExitStack):
"""Testing utility that patches get_user_acl results

Can be used as decorator or context manager.

Patch should be a dict or callable.
"""

_acl_patches = []

def __init__(self, acl_patch):
super().__init__()
self.acl_patch = acl_patch

def patched_get_user_acl(self, user, cache_versions):
user_acl = get_user_acl(user, cache_versions)
self.apply_acl_patches(user, user_acl)
return user_acl

def apply_acl_patches(self, user, user_acl):
for acl_patch in self._acl_patches:
self.apply_acl_patch(user, user_acl, acl_patch)

def apply_acl_patch(self, user, user_acl, acl_patch):
if callable(acl_patch):
acl_patch(user, user_acl)
else:
user_acl.update(acl_patch)

def __enter__(self):
super().__enter__()
self.enter_context(self.enable_acl_patch())
self.enter_context(self.patch_user_acl())

@contextmanager
def enable_acl_patch(self):
try:
self._acl_patches.append(self.acl_patch)
yield
finally:
self._acl_patches.pop(-1)

def patch_user_acl(self):
return patch(
"misago.acl.useracl.get_user_acl",
side_effect=self.patched_get_user_acl,
)
Loading