Project

General

Profile

0004-Add-middleware-to-load-settings-from-a-JSON-file-bas.patch

Benjamin Dauvergne, 11 September 2014 04:00 PM

Download (5.14 KB)

View differences:

Subject: [PATCH 04/11] Add middleware to load settings from a JSON file based
 on the tenant

* Loaded settings are cached based on the mtime of the setting file
* JSON file path is <settings.TENANT_BASE>/<schema_name>/settings.json
 entrouvert/djommon/multitenant/middleware.py |  108 ++++++++++++++++++++++++++
 1 file changed, 108 insertions(+)
entrouvert/djommon/multitenant/middleware.py
1
import os
2
import json
3

  
1 4
from django.conf import settings, UserSettingsHolder
2 5

  
3 6
from tenant_schemas.middleware import TenantMiddleware
......
18 21
    def process_response(self, request, response):
19 22
        settings._wrapped = self.wrapped
20 23
        return response
24

  
25
class TenantSettingBaseMiddleware(object):
26
    '''Base middleware classe for loading settings based on tenants
27

  
28
       Child classes MUST override the load_tenant_settings() method.
29
    '''
30
    def __init__(self, *args, **kwargs):
31
        self.tenants_settings = {}
32

  
33
    def get_tenant_settings(self, wrapped, tenant):
34
        '''Get last loaded settings for tenant, try to update it by loading
35
           settings again is last loading time is less recent thant settings data
36
           store. Compare with last modification time is done in the
37
           load_tenant_settings() method.
38
        '''
39
        tenant_settings, last_time = self.tenants_settings.get(tenant.schema_name, (None,None))
40
        if tenant_settings is None:
41
            tenant_settings = UserSettingsHolder(wrapped)
42
        tenant_settings, last_time = self.load_tenant_settings(wrapped, tenant, tenant_settings, last_time)
43
        self.tenants_settings[tenant.schema_name] = tenant_settings, last_time
44
        return tenant_settings
45

  
46
    def load_tenant_settings(self, wrapped, tenant, tenant_settings, last_time):
47
        '''Load tenant settings into tenant_settings object, eventually skip if
48
           last_time is more recent than last update time for settings and return
49
           the new value for tenant_settings and last_time'''
50
        raise NotImplemented
51

  
52
    def process_request(self, request):
53
        if not hasattr(request, '_old_settings_wrapped'):
54
            request._old_settings_wrapped = []
55
        request._old_settings_wrapped.append(settings._wrapped)
56
        settings._wrapped = self.get_tenant_settings(settings._wrapped, request.tenant)
57

  
58
    def process_response(self, request, response):
59
        if hasattr(request, '_old_settings_wrapped') and request._old_settings_wrapped:
60
            settings._wrapped = request._old_settings_wrapped.pop()
61
        return response
62

  
63

  
64
class FileBasedTenantSettingBaseMiddleware(TenantSettingBaseMiddleware):
65
    FILENAME = None
66

  
67
    def load_tenant_settings(self, wrapped, tenant, tenant_settings, last_time):
68
        path = os.path.join(settings.TENANT_BASE, tenant.schema_name, self.FILENAME)
69
        try:
70
            new_time = os.stat(path).st_mtime
71
        except OSError:
72
            # file was removed
73
            if not last_time is None:
74
                return UserSettingsHolder(wrapped), None
75
        else:
76
            if last_time is None or new_time >= last_time:
77
                # file is new
78
                tenant_settings = UserSettingsHolder(wrapped)
79
                self.load_file(tenant_settings, path)
80
                return tenant_settings, new_time
81
        # nothing has changed
82
        return tenant_settings, last_time
83

  
84

  
85
class JSONSettingsMiddleware(FileBasedTenantSettingBaseMiddleware):
86
    '''Load settings from a JSON file whose path is given by:
87

  
88
            os.path.join(settings.TENANT_BASE % schema_name, 'settings.json')
89

  
90
       The JSON file must be a dictionnary whose key/value will override
91
       current settings.
92
    '''
93
    FILENAME = 'settings.json'
94

  
95
    def load_file(sef, tenant_settings, path):
96
        with file(path) as f:
97
            json_settings = json.load(f)
98
            for key in json_settings:
99
                setattr(tenant_settings, key, json_settings[key])
100

  
101

  
102
class DictAdapter(dict):
103
    '''Give dict interface to plain objects'''
104
    def __init__(self, wrapped):
105
        self.wrapped = wrapped
106

  
107
    def __setitem__(self, key, value):
108
        setattr(self.wrapped, key, value)
109

  
110
    def __getitem__(self, key):
111
        try:
112
            return getattr(self.wrapped, key)
113
        except AttributeError:
114
            raise KeyError
115

  
116

  
117
class PythonSettingsMiddleware(JSONSettingsMiddleware):
118
    '''Load settings from a file whose path is given by:
119

  
120
            os.path.join(settings.TENANT_BASE % schema_name, 'settings.py')
121

  
122
       The file is executed in the same context as the classic settings file
123
       using execfile.
124
    '''
125
    FILENAME = 'settings.py'
126

  
127
    def load_file(self, tenant_settings, path):
128
        execfile(path, DictAdapter(tenant_settings))
21
-