Completed
Push — develop ( 10efb0...b51ddf )
by Bastien
16s queued 14s
created

backend.tracim_backend.config.CFG.__setattr__()   A

Complexity

Conditions 5

Size

Total Lines 21
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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