backend.tracim_backend.config.CFG.__init__()   F
last analyzed

Complexity

Conditions 26

Size

Total Lines 537
Code Lines 265

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 265
dl 0
loc 537
rs 0
c 0
b 0
f 0
cc 26
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like backend.tracim_backend.config.CFG.__init__() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
import json
3
from collections import OrderedDict
4
from urllib.parse import urlparse
5
6
import os
7
8
import typing
9
10
from paste.deploy.converters import asbool
11
from tracim_backend.app_models.validator import update_validators
12
from tracim_backend.extensions import app_list
13
from tracim_backend.lib.utils.logger import logger
14
from depot.manager import DepotManager
15
from tracim_backend.app_models.applications import Application
16
from tracim_backend.app_models.contents import content_type_list
17
from tracim_backend.app_models.contents import content_status_list
18
from tracim_backend.models import Group
19
from tracim_backend.models.data import ActionDescription
20
21
22
class CFG(object):
23
    """Object used for easy access to config file parameters."""
24
25
    def __setattr__(self, key, value):
26
        """
27
        Log-ready setter.
28
29
        Logs all configuration parameters except password.
30
        :param key:
31
        :param value:
32
        :return:
33
        """
34
        if 'PASSWORD' not in key and \
35
                ('URL' not in key or type(value) == str) and \
36
                'CONTENT' not in key:
37
            # We do not show PASSWORD for security reason
38
            # we do not show URL because At the time of configuration setup,
39
            # it can't be evaluated
40
            # We do not show CONTENT in order not to pollute log files
41
            logger.info(self, 'CONFIG: [ {} | {} ]'.format(key, value))
42
        else:
43
            logger.info(self, 'CONFIG: [ {} | <value not shown> ]'.format(key))
44
45
        self.__dict__[key] = value
46
47
    def __init__(self, settings):
48
        """Parse configuration file."""
49
50
        ###
51
        # General
52
        ###
53
        backend_folder = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # nopep8
54
        tracim_v2_folder = os.path.dirname(backend_folder)
55
        default_color_config_file_path = os.path.join(tracim_v2_folder, 'color.json')  # nopep8
56
        self.COLOR_CONFIG_FILE_PATH = settings.get(
57
            'color.config_file_path', default_color_config_file_path
58
        )
59
        if not os.path.exists(self.COLOR_CONFIG_FILE_PATH):
60
            raise Exception(
61
                'ERROR: {} file does not exist. '
62
                'please create it or set color.config_file_path'
63
                'with a correct value'.format(self.COLOR_CONFIG_FILE_PATH)
64
            )
65
66
        try:
67
            with open(self.COLOR_CONFIG_FILE_PATH) as json_file:
68
                self.APPS_COLORS = json.load(json_file)
69
        except Exception as e:
70
            raise Exception(
71
                'Error: {} file could not be load as json'.format(self.COLOR_CONFIG_FILE_PATH) # nopep8
72
            ) from e
73
74
        try:
75
            self.APPS_COLORS['primary']
76
        except KeyError as e:
77
            raise Exception(
78
                'Error: primary color is required in {} file'.format(
79
                    self.COLOR_CONFIG_FILE_PATH)  # nopep8
80
            ) from e
81
82
        default_enabled_app = [
83
            'contents/thread',
84
            'contents/file',
85
            'contents/html-document',
86
        ]
87
        enabled_app = []
88
        enabled_app_str = settings.get('app.enabled', None)
89
        if enabled_app_str:
90
            for app in enabled_app_str.split(','):
91
                app_name = app.strip()
92
                enabled_app.append(app_name)
93
        else:
94
            enabled_app = default_enabled_app
95
        self.ENABLED_APP = enabled_app
96
        self._set_default_app(self.ENABLED_APP)
97
        mandatory_msg = \
98
            'ERROR: {} configuration is mandatory. Set it before continuing.'
99
        self.DEPOT_STORAGE_DIR = settings.get(
100
            'depot_storage_dir',
101
        )
102
        if not self.DEPOT_STORAGE_DIR:
103
            raise Exception(
104
                mandatory_msg.format('depot_storage_dir')
105
            )
106
        self.DEPOT_STORAGE_NAME = settings.get(
107
            'depot_storage_name',
108
        )
109
        if not self.DEPOT_STORAGE_NAME:
110
            raise Exception(
111
                mandatory_msg.format('depot_storage_name')
112
            )
113
        self.PREVIEW_CACHE_DIR = settings.get(
114
            'preview_cache_dir',
115
        )
116
        if not self.PREVIEW_CACHE_DIR:
117
            raise Exception(
118
                'ERROR: preview_cache_dir configuration is mandatory. '
119
                'Set it before continuing.'
120
            )
121
122
        # TODO - G.M - 2018-09-11 - Deprecated param
123
        # self.DATA_UPDATE_ALLOWED_DURATION = int(settings.get(
124
        #     'content.update.allowed.duration',
125
        #     0,
126
        # ))
127
128
        self.API_KEY = settings.get(
129
            'api.key',
130
            ''
131
        )
132
        self.SESSION_REISSUE_TIME = int(settings.get(
133
            'session.reissue_time',
134
            120
135
        ))
136
        self.WEBSITE_TITLE = settings.get(
137
            'website.title',
138
            'TRACIM',
139
        )
140
141
        # base url of the frontend
142
        self.WEBSITE_BASE_URL = settings.get(
143
            'website.base_url',
144
            '',
145
        )
146
        if not self.WEBSITE_BASE_URL:
147
            raise Exception(
148
                'website.base_url is needed in order to have correct path in'
149
                'few place like in email.'
150
                'You should set it with frontend root url.'
151
            )
152
153
        self.API_BASE_URL = settings.get(
154
            'api.base_url',
155
            self.WEBSITE_BASE_URL,
156
        )
157
        allowed_origin = []
158
        allowed_origin_string = settings.get(
159
            'cors.access-control-allowed-origin',
160
            ''
161
        )
162
        if allowed_origin_string:
163
            allowed_origin.extend(allowed_origin_string.split(','))  # nopep8
164
        if not allowed_origin:
165
            allowed_origin.append(self.WEBSITE_BASE_URL)
166
            if self.API_BASE_URL != self.WEBSITE_BASE_URL:
167
                allowed_origin.append(self.API_BASE_URL)
168
        self.CORS_ALLOWED_ORIGIN = allowed_origin
169
170
        # TODO - G.M - 26-03-2018 - [Cleanup] These params seems deprecated for tracimv2,  # nopep8
171
        # Verify this
172
        #
173
        # self.WEBSITE_HOME_TITLE_COLOR = settings.get(
174
        #     'website.title.color',
175
        #     '#555',
176
        # )
177
        # self.WEBSITE_HOME_IMAGE_PATH = settings.get(
178
        #     '/assets/img/home_illustration.jpg',
179
        # )
180
        # self.WEBSITE_HOME_BACKGROUND_IMAGE_PATH = settings.get(
181
        #     '/assets/img/bg.jpg',
182
        # )
183
        #
184
        website_server_name = settings.get(
185
            'website.server_name',
186
            None,
187
        )
188
        if not website_server_name:
189
            website_server_name= urlparse(self.WEBSITE_BASE_URL).hostname
190
            logger.warning(
191
                self,
192
                'NOTE: Generated website.server_name parameter from '
193
                'website.base_url parameter -> {0}'
194
                .format(website_server_name)
195
            )
196
        self.WEBSITE_SERVER_NAME = website_server_name
197
        # TODO - G.M - 2018-09-11 - Deprecated params
198
        # self.WEBSITE_HOME_TAG_LINE = settings.get(
199
        #     'website.home.tag_line',
200
        #     '',
201
        # )
202
        # self.WEBSITE_SUBTITLE = settings.get(
203
        #     'website.home.subtitle',
204
        #     '',
205
        # )
206
        # self.WEBSITE_HOME_BELOW_LOGIN_FORM = settings.get(
207
        #     'website.home.below_login_form',
208
        #     '',
209
        # )
210
        #
211
        # self.WEBSITE_TREEVIEW_CONTENT = settings.get(
212
        #     'website.treeview.content',
213
        # )
214
215
        self.USER_AUTH_TOKEN_VALIDITY = int(settings.get(
216
            'user.auth_token.validity',
217
            '604800',
218
        ))
219
        self.USER_RESET_PASSWORD_TOKEN_VALIDITY = int(settings.get(
220
            'user.reset_password.validity',
221
            '900'
222
        ))
223
224
        self.DEBUG = asbool(settings.get('debug', False))
225
        # TODO - G.M - 27-03-2018 - [Email] Restore email config
226
        ###
227
        # EMAIL related stuff (notification, reply)
228
        ##
229
230
        self.EMAIL_NOTIFICATION_NOTIFIED_EVENTS = [
231
            ActionDescription.COMMENT,
232
            ActionDescription.CREATION,
233
            ActionDescription.EDITION,
234
            ActionDescription.REVISION,
235
            ActionDescription.STATUS_UPDATE
236
        ]
237
238
        self.EMAIL_NOTIFICATION_NOTIFIED_CONTENTS = [
239
            content_type_list.Page.slug,
240
            content_type_list.Thread.slug,
241
            content_type_list.File.slug,
242
            content_type_list.Comment.slug,
243
            # content_type_list.Folder.slug -- Folder is skipped
244
        ]
245
        if settings.get('email.notification.from'):
246
            raise Exception(
247
                'email.notification.from configuration is deprecated. '
248
                'Use instead email.notification.from.email and '
249
                'email.notification.from.default_label.'
250
            )
251
        self.EMAIL_NOTIFICATION_FROM_EMAIL = settings.get(
252
            'email.notification.from.email',
253
            'noreply+{user_id}@trac.im'
254
        )
255
        self.EMAIL_NOTIFICATION_FROM_DEFAULT_LABEL = settings.get(
256
            'email.notification.from.default_label',
257
            'Tracim Notifications'
258
        )
259
        self.EMAIL_NOTIFICATION_REPLY_TO_EMAIL = settings.get(
260
            'email.notification.reply_to.email',
261
        )
262
        self.EMAIL_NOTIFICATION_REFERENCES_EMAIL = settings.get(
263
            'email.notification.references.email'
264
        )
265
        # Content update notification
266
        self.EMAIL_NOTIFICATION_CONTENT_UPDATE_TEMPLATE_HTML = settings.get(
267
            'email.notification.content_update.template.html',
268
        )
269
        self.EMAIL_NOTIFICATION_CONTENT_UPDATE_TEMPLATE_TEXT = settings.get(
270
            'email.notification.content_update.template.text',
271
        )
272
        self.EMAIL_NOTIFICATION_CONTENT_UPDATE_SUBJECT = settings.get(
273
            'email.notification.content_update.subject',
274
        )
275
        # Created account notification
276
        self.EMAIL_NOTIFICATION_CREATED_ACCOUNT_TEMPLATE_HTML = settings.get(
277
            'email.notification.created_account.template.html',
278
            './tracim_backend/templates/mail/created_account_body_html.mak',
279
        )
280
        self.EMAIL_NOTIFICATION_CREATED_ACCOUNT_TEMPLATE_TEXT = settings.get(
281
            'email.notification.created_account.template.text',
282
            './tracim_backend/templates/mail/created_account_body_text.mak',
283
        )
284
        self.EMAIL_NOTIFICATION_CREATED_ACCOUNT_SUBJECT = settings.get(
285
            'email.notification.created_account.subject',
286
            '[{website_title}] Created account',
287
        )
288
289
        # Reset password notification
290
        self.EMAIL_NOTIFICATION_RESET_PASSWORD_TEMPLATE_HTML = settings.get(
291
            'email.notification.reset_password_request.template.html',
292
            './tracim_backend/templates/mail/reset_password_body_html.mak',
293
        )
294
        self.EMAIL_NOTIFICATION_RESET_PASSWORD_TEMPLATE_TEXT = settings.get(
295
            'email.notification.reset_password_request.template.text',
296
            './tracim_backend/templates/mail/reset_password_body_text.mak',
297
        )
298
        self.EMAIL_NOTIFICATION_RESET_PASSWORD_SUBJECT = settings.get(
299
            'email.notification.reset_password_request.subject',
300
            '[{website_title}] Reset Password Request'
301
        )
302
303
        self.EMAIL_NOTIFICATION_PROCESSING_MODE = settings.get(
304
            'email.notification.processing_mode',
305
        )
306
307
        self.EMAIL_NOTIFICATION_ACTIVATED = asbool(settings.get(
308
            'email.notification.activated',
309
        ))
310
        if not self.EMAIL_NOTIFICATION_ACTIVATED:
311
            logger.warning(
312
                self,
313
                'Notification by email mecanism is disabled ! '
314
                'Notification and mail invitation mecanisms will not work.'
315
            )
316
        self.EMAIL_NOTIFICATION_SMTP_SERVER = settings.get(
317
            'email.notification.smtp.server',
318
        )
319
        self.EMAIL_NOTIFICATION_SMTP_PORT = settings.get(
320
            'email.notification.smtp.port',
321
        )
322
        self.EMAIL_NOTIFICATION_SMTP_USER = settings.get(
323
            'email.notification.smtp.user',
324
        )
325
        self.EMAIL_NOTIFICATION_SMTP_PASSWORD = settings.get(
326
            'email.notification.smtp.password',
327
        )
328
        self.EMAIL_NOTIFICATION_LOG_FILE_PATH = settings.get(
329
            'email.notification.log_file_path',
330
            None,
331
        )
332
333
        self.EMAIL_REPLY_ACTIVATED = asbool(settings.get(
334
            'email.reply.activated',
335
            False,
336
        ))
337
338
        self.EMAIL_REPLY_IMAP_SERVER = settings.get(
339
            'email.reply.imap.server',
340
        )
341
        self.EMAIL_REPLY_IMAP_PORT = settings.get(
342
            'email.reply.imap.port',
343
        )
344
        self.EMAIL_REPLY_IMAP_USER = settings.get(
345
            'email.reply.imap.user',
346
        )
347
        self.EMAIL_REPLY_IMAP_PASSWORD = settings.get(
348
            'email.reply.imap.password',
349
        )
350
        self.EMAIL_REPLY_IMAP_FOLDER = settings.get(
351
            'email.reply.imap.folder',
352
        )
353
        self.EMAIL_REPLY_CHECK_HEARTBEAT = int(settings.get(
354
            'email.reply.check.heartbeat',
355
            60,
356
        ))
357
        self.EMAIL_REPLY_TOKEN = settings.get(
358
            'email.reply.token',
359
        )
360
        self.EMAIL_REPLY_IMAP_USE_SSL = asbool(settings.get(
361
            'email.reply.imap.use_ssl',
362
        ))
363
        self.EMAIL_REPLY_IMAP_USE_IDLE = asbool(settings.get(
364
            'email.reply.imap.use_idle',
365
            True,
366
        ))
367
        self.EMAIL_REPLY_CONNECTION_MAX_LIFETIME = int(settings.get(
368
            'email.reply.connection.max_lifetime',
369
            600,  # 10 minutes
370
        ))
371
        self.EMAIL_REPLY_USE_HTML_PARSING = asbool(settings.get(
372
            'email.reply.use_html_parsing',
373
            True,
374
        ))
375
        self.EMAIL_REPLY_USE_TXT_PARSING = asbool(settings.get(
376
            'email.reply.use_txt_parsing',
377
            True,
378
        ))
379
        self.EMAIL_REPLY_LOCKFILE_PATH = settings.get(
380
            'email.reply.lockfile_path',
381
            ''
382
        )
383
        if not self.EMAIL_REPLY_LOCKFILE_PATH and self.EMAIL_REPLY_ACTIVATED:
384
            raise Exception(
385
                mandatory_msg.format('email.reply.lockfile_path')
386
            )
387
388
        self.EMAIL_PROCESSING_MODE = settings.get(
389
            'email.processing_mode',
390
            'sync',
391
        ).upper()
392
393
        if self.EMAIL_PROCESSING_MODE not in (
394
                self.CST.ASYNC,
395
                self.CST.SYNC,
396
        ):
397
            raise Exception(
398
                'email.processing_mode '
399
                'can ''be "{}" or "{}", not "{}"'.format(
400
                    self.CST.ASYNC,
401
                    self.CST.SYNC,
402
                    self.EMAIL_PROCESSING_MODE,
403
                )
404
            )
405
406
        self.EMAIL_SENDER_REDIS_HOST = settings.get(
407
            'email.async.redis.host',
408
            'localhost',
409
        )
410
        self.EMAIL_SENDER_REDIS_PORT = int(settings.get(
411
            'email.async.redis.port',
412
            6379,
413
        ))
414
        self.EMAIL_SENDER_REDIS_DB = int(settings.get(
415
            'email.async.redis.db',
416
            0,
417
        ))
418
        self.INVITE_NEW_USER_MINIMAL_PROFILE = settings.get(
419
            'invitation.new_user.minimal_profile',
420
            Group.TIM_MANAGER_GROUPNAME
421
        )
422
        ###
423
        # WSGIDAV (Webdav server)
424
        ###
425
426
        # TODO - G.M - 27-03-2018 - [WebDav] Restore wsgidav config
427
        #self.WSGIDAV_CONFIG_PATH = settings.get(
428
        #    'wsgidav.config_path',
429
        #    'wsgidav.conf',
430
        #)
431
        # TODO: Convert to importlib
432
        # http://stackoverflow.com/questions/41063938/use-importlib-instead-imp-for-non-py-file
433
        #self.wsgidav_config = imp.load_source(
434
        #    'wsgidav_config',
435
        #    self.WSGIDAV_CONFIG_PATH,
436
        #)
437
        # self.WSGIDAV_PORT = self.wsgidav_config.port
438
        # self.WSGIDAV_CLIENT_BASE_URL = settings.get(
439
        #     'wsgidav.client.base_url',
440
        #     None,
441
        # )
442
        #
443
        # if not self.WSGIDAV_CLIENT_BASE_URL:
444
        #     self.WSGIDAV_CLIENT_BASE_URL = \
445
        #         '{0}:{1}'.format(
446
        #             self.WEBSITE_SERVER_NAME,
447
        #             self.WSGIDAV_PORT,
448
        #         )
449
        #     logger.warning(self,
450
        #         'NOTE: Generated wsgidav.client.base_url parameter with '
451
        #         'followings parameters: website.server_name and '
452
        #         'wsgidav.conf port'.format(
453
        #             self.WSGIDAV_CLIENT_BASE_URL,
454
        #         )
455
        #     )
456
        #
457
        # if not self.WSGIDAV_CLIENT_BASE_URL.endswith('/'):
458
        #     self.WSGIDAV_CLIENT_BASE_URL += '/'
459
460
        # TODO - G.M - 27-03-2018 - [Caldav] Restore radicale config
461
        ###
462
        # RADICALE (Caldav server)
463
        ###
464
        # self.RADICALE_SERVER_HOST = settings.get(
465
        #     'radicale.server.host',
466
        #     '127.0.0.1',
467
        # )
468
        # self.RADICALE_SERVER_PORT = int(settings.get(
469
        #     'radicale.server.port',
470
        #     5232,
471
        # ))
472
        # # Note: Other parameters needed to work in SSL (cert file, etc)
473
        # self.RADICALE_SERVER_SSL = asbool(settings.get(
474
        #     'radicale.server.ssl',
475
        #     False,
476
        # ))
477
        # self.RADICALE_SERVER_FILE_SYSTEM_FOLDER = settings.get(
478
        #     'radicale.server.filesystem.folder',
479
        # )
480
        # if not self.RADICALE_SERVER_FILE_SYSTEM_FOLDER:
481
        #     raise Exception(
482
        #         mandatory_msg.format('radicale.server.filesystem.folder')
483
        #     )
484
        # self.RADICALE_SERVER_ALLOW_ORIGIN = settings.get(
485
        #     'radicale.server.allow_origin',
486
        #     None,
487
        # )
488
        # if not self.RADICALE_SERVER_ALLOW_ORIGIN:
489
        #     self.RADICALE_SERVER_ALLOW_ORIGIN = self.WEBSITE_BASE_URL
490
        #     logger.warning(self,
491
        #         'NOTE: Generated radicale.server.allow_origin parameter with '
492
        #         'followings parameters: website.base_url ({0})'
493
        #         .format(self.WEBSITE_BASE_URL)
494
        #     )
495
        #
496
        # self.RADICALE_SERVER_REALM_MESSAGE = settings.get(
497
        #     'radicale.server.realm_message',
498
        #     'Tracim Calendar - Password Required',
499
        # )
500
        #
501
        # self.RADICALE_CLIENT_BASE_URL_HOST = settings.get(
502
        #     'radicale.client.base_url.host',
503
        #     'http://{}:{}'.format(
504
        #         self.RADICALE_SERVER_HOST,
505
        #         self.RADICALE_SERVER_PORT,
506
        #     ),
507
        # )
508
        #
509
        # self.RADICALE_CLIENT_BASE_URL_PREFIX = settings.get(
510
        #     'radicale.client.base_url.prefix',
511
        #     '/',
512
        # )
513
        # # Ensure finished by '/'
514
        # if '/' != self.RADICALE_CLIENT_BASE_URL_PREFIX[-1]:
515
        #     self.RADICALE_CLIENT_BASE_URL_PREFIX += '/'
516
        # if '/' != self.RADICALE_CLIENT_BASE_URL_PREFIX[0]:
517
        #     self.RADICALE_CLIENT_BASE_URL_PREFIX \
518
        #         = '/' + self.RADICALE_CLIENT_BASE_URL_PREFIX
519
        #
520
        # if not self.RADICALE_CLIENT_BASE_URL_HOST:
521
        #     logger.warning(self,
522
        #         'Generated radicale.client.base_url.host parameter with '
523
        #         'followings parameters: website.server_name -> {}'
524
        #         .format(self.WEBSITE_SERVER_NAME)
525
        #     )
526
        #     self.RADICALE_CLIENT_BASE_URL_HOST = self.WEBSITE_SERVER_NAME
527
        #
528
        # self.RADICALE_CLIENT_BASE_URL_TEMPLATE = '{}{}'.format(
529
        #     self.RADICALE_CLIENT_BASE_URL_HOST,
530
        #     self.RADICALE_CLIENT_BASE_URL_PREFIX,
531
        # )
532
        self.PREVIEW_JPG_RESTRICTED_DIMS = asbool(settings.get(
533
            'preview.jpg.restricted_dims', False
534
        ))
535
        preview_jpg_allowed_dims_str = settings.get('preview.jpg.allowed_dims', '')  # nopep8
536
        allowed_dims = []
537
        if preview_jpg_allowed_dims_str:
538
            for sizes in preview_jpg_allowed_dims_str.split(','):
539
                parts = sizes.split('x')
540
                assert len(parts) == 2
541
                width, height = parts
542
                assert width.isdecimal()
543
                assert height.isdecimal()
544
                size = PreviewDim(int(width), int(height))
545
                allowed_dims.append(size)
546
547
        if not allowed_dims:
548
            size = PreviewDim(256, 256)
549
            allowed_dims.append(size)
550
551
        self.PREVIEW_JPG_ALLOWED_DIMS = allowed_dims
552
553
        self.FRONTEND_SERVE = asbool(settings.get(
554
            'frontend.serve', False
555
        ))
556
        # INFO - G.M - 2018-08-06 - we pretend that frontend_dist_folder
557
        # is probably in frontend subfolder
558
        # of tracim_v2 parent of both backend and frontend
559
        backend_folder = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # nopep8
560
        tracim_v2_folder = os.path.dirname(backend_folder)
561
        backend_i18n_folder = os.path.join(backend_folder,'tracim_backend', 'locale')  # nopep8
562
563
        self.BACKEND_I18N_FOLDER = settings.get(
564
            'backend.18n_folder_path', backend_i18n_folder
565
        )
566
        if not os.path.isdir(self.BACKEND_I18N_FOLDER):
567
            raise Exception(
568
                'ERROR: {} folder does not exist as folder. '
569
                'please set backend.i8n_folder_path'
570
                'with a correct value'.format(self.BACKEND_I18N_FOLDER)
571
            )
572
573
        frontend_dist_folder = os.path.join(tracim_v2_folder, 'frontend', 'dist')  # nopep8
574
        self.FRONTEND_DIST_FOLDER_PATH = settings.get(
575
            'frontend.dist_folder_path', frontend_dist_folder
576
        )
577
578
        # INFO - G.M - 2018-08-06 - We check dist folder existence
579
        if self.FRONTEND_SERVE and not os.path.isdir(self.FRONTEND_DIST_FOLDER_PATH):  # nopep8
580
            raise Exception(
581
                'ERROR: {} folder does not exist as folder. '
582
                'please set frontend.dist_folder.path'
583
                'with a correct value'.format(self.FRONTEND_DIST_FOLDER_PATH)
584
            )
585
586
    def configure_filedepot(self):
587
588
        # TODO - G.M - 2018-08-08 - [GlobalVar] Refactor Global var
589
        # of tracim_backend, Be careful DepotManager is a Singleton !
590
591
        depot_storage_name = self.DEPOT_STORAGE_NAME
592
        depot_storage_path = self.DEPOT_STORAGE_DIR
593
        depot_storage_settings = {'depot.storage_path': depot_storage_path}
594
        DepotManager.configure(
595
            depot_storage_name,
596
            depot_storage_settings,
597
        )
598
599
    def _set_default_app(self, enabled_app_list: typing.List[str]):
600
601
        # init applications
602
        html_documents = Application(
603
            label='Text Documents',  # TODO - G.M - 24-05-2018 - Check label
604
            slug='contents/html-document',
605
            fa_icon='file-text-o',
606
            is_active=True,
607
            config={},
608
            main_route='/ui/workspaces/{workspace_id}/contents?type=html-document',
609
            app_config=self
610
        )
611
        html_documents.add_content_type(
612
            slug='html-document',
613
            label='Text Document',
614
            creation_label='Write a document',
615
            available_statuses=content_status_list.get_all(),
616
            slug_alias=['page'],
617
            file_extension='.document.html',
618
        )
619
620
        _file = Application(
621
            label='Files',
622
            slug='contents/file',
623
            fa_icon='paperclip',
624
            is_active=True,
625
            config={},
626
            main_route='/ui/workspaces/{workspace_id}/contents?type=file',
627
            app_config=self,
628
        )
629
        _file.add_content_type(
630
            slug='file',
631
            label='File',
632
            creation_label='Upload a file',
633
            available_statuses=content_status_list.get_all(),
634
        )
635
636
        thread = Application(
637
            label='Threads',
638
            slug='contents/thread',
639
            fa_icon='comments-o',
640
            is_active=True,
641
            config={},
642
            main_route='/ui/workspaces/{workspace_id}/contents?type=thread',
643
            app_config=self
644
        )
645
        thread.add_content_type(
646
            slug='thread',
647
            label='Thread',
648
            creation_label='Start a topic',
649
            available_statuses=content_status_list.get_all(),
650
            file_extension='.thread.html'
651
        )
652
653
        folder = Application(
654
            label='Folder',
655
            slug='contents/folder',
656
            fa_icon='folder-open-o',
657
            is_active=True,
658
            config={},
659
            main_route='',
660
            app_config=self
661
        )
662
        folder.add_content_type(
663
            slug='folder',
664
            label='Folder',
665
            creation_label='Create a folder',
666
            available_statuses=content_status_list.get_all(),
667
            allow_sub_content=True,
668
        )
669
670
        markdownpluspage = Application(
671
            label='Markdown Plus Documents',
672
            # TODO - G.M - 24-05-2018 - Check label
673
            slug='contents/markdownpluspage',
674
            fa_icon='file-code-o',
675
            is_active=False,
676
            config={},
677
            main_route='/ui/workspaces/{workspace_id}/contents?type=markdownpluspage',
678
            # nopep8
679
            app_config=self,
680
        )
681
        markdownpluspage.add_content_type(
682
            slug='markdownpage',
683
            label='Rich Markdown File',
684
            creation_label='Create a Markdown document',
685
            available_statuses=content_status_list.get_all(),
686
        )
687
688
        calendar = Application(
689
            label='Calendar',
690
            slug='calendar',
691
            fa_icon='calendar',
692
            is_active=False,
693
            config={},
694
            main_route='/ui/workspaces/{workspace_id}/calendar',
695
            app_config=self
696
        )
697
698
        # process activated app list
699
        available_apps = OrderedDict([
700
            (html_documents.slug, html_documents),
701
            (_file.slug, _file),
702
            (thread.slug, thread),
703
            (folder.slug, folder),
704
            (markdownpluspage.slug, markdownpluspage),
705
            (calendar.slug, calendar)
706
        ])
707
        # TODO - G.M - 2018-08-08 - [GlobalVar] Refactor Global var
708
        # of tracim_backend, Be careful app_list is a global_var
709
        app_list.clear()
710
        for app_slug in enabled_app_list:
711
            if app_slug in available_apps.keys():
712
                app_list.append(available_apps[app_slug])
713
        # TODO - G.M - 2018-08-08 - We need to update validators each time
714
        # app_list is updated.
715
        update_validators()
716
717
    class CST(object):
718
        ASYNC = 'ASYNC'
719
        SYNC = 'SYNC'
720
721
        TREEVIEW_FOLDERS = 'folders'
722
        TREEVIEW_ALL = 'all'
723
724
725
class PreviewDim(object):
726
727
    def __init__(self, width: int, height: int) -> None:
728
        self.width = width
729
        self.height = height
730
731
    def __repr__(self):
732
        return "<PreviewDim width:{width} height:{height}>".format(
733
            width=self.width,
734
            height=self.height,
735
        )
736