Browse Source

Merge pull request #25 from tracim/feature/734_add_lang_to_user

Bastien Sevajol 6 years ago
parent
commit
54f62ebe19
No account linked to committer's email

+ 6 - 0
backend/tracim_backend/lib/core/user.py View File

314
             email: str=None,
314
             email: str=None,
315
             password: str=None,
315
             password: str=None,
316
             timezone: str=None,
316
             timezone: str=None,
317
+            lang: str=None,
317
             groups: typing.Optional[typing.List[Group]]=None,
318
             groups: typing.Optional[typing.List[Group]]=None,
318
             do_save=True,
319
             do_save=True,
319
     ) -> User:
320
     ) -> User:
330
         if timezone is not None:
331
         if timezone is not None:
331
             user.timezone = timezone
332
             user.timezone = timezone
332
 
333
 
334
+        if lang is not None:
335
+            user.lang = lang
336
+
333
         if groups is not None:
337
         if groups is not None:
334
             # INFO - G.M - 2018-07-18 - Delete old groups
338
             # INFO - G.M - 2018-07-18 - Delete old groups
335
             for group in user.groups:
339
             for group in user.groups:
351
         password: str = None,
355
         password: str = None,
352
         name: str = None,
356
         name: str = None,
353
         timezone: str = '',
357
         timezone: str = '',
358
+        lang: str= None,
354
         groups=[],
359
         groups=[],
355
         do_save: bool=True,
360
         do_save: bool=True,
356
         do_notify: bool=True,
361
         do_notify: bool=True,
362
             email=email,
367
             email=email,
363
             password=password,
368
             password=password,
364
             timezone=timezone,
369
             timezone=timezone,
370
+            lang=lang,
365
             do_save=False,
371
             do_save=False,
366
         )
372
         )
367
         if do_notify:
373
         if do_notify:

+ 26 - 0
backend/tracim_backend/migration/versions/a143b60aad61_add_lang_to_user.py View File

1
+"""add lang to user
2
+
3
+Revision ID: a143b60aad61
4
+Revises: 78b52ca39419
5
+Create Date: 2018-08-20 10:17:14.859250
6
+
7
+"""
8
+
9
+# revision identifiers, used by Alembic.
10
+revision = 'a143b60aad61'
11
+down_revision = '78b52ca39419'
12
+
13
+from alembic import op
14
+import sqlalchemy as sa
15
+
16
+
17
+def upgrade():
18
+    # ### commands auto generated by Alembic - please adjust! ###
19
+    op.add_column('users', sa.Column('lang', sa.Unicode(length=3), nullable=True))  # nopep8
20
+    # ### end Alembic commands ###
21
+
22
+
23
+def downgrade():
24
+    # ### commands auto generated by Alembic - please adjust! ###
25
+    op.drop_column('users', 'lang')
26
+    # ### end Alembic commands ###

+ 3 - 0
backend/tracim_backend/models/auth.py View File

138
     is_active = Column(Boolean, default=True, nullable=False)
138
     is_active = Column(Boolean, default=True, nullable=False)
139
     is_deleted = Column(Boolean, default=False, nullable=False, server_default=sqlalchemy.sql.expression.literal(False))
139
     is_deleted = Column(Boolean, default=False, nullable=False, server_default=sqlalchemy.sql.expression.literal(False))
140
     imported_from = Column(Unicode(32), nullable=True)
140
     imported_from = Column(Unicode(32), nullable=True)
141
+    # timezone as tz database format
141
     timezone = Column(Unicode(255), nullable=False, server_default='')
142
     timezone = Column(Unicode(255), nullable=False, server_default='')
143
+    # lang in iso639 format
144
+    lang = Column(Unicode(3), nullable=True, default=None)
142
     # TODO - G.M - 04-04-2018 - [auth] Check if this is already needed
145
     # TODO - G.M - 04-04-2018 - [auth] Check if this is already needed
143
     # with new auth system
146
     # with new auth system
144
     auth_token = Column(Unicode(255))
147
     auth_token = Column(Unicode(255))

+ 8 - 1
backend/tracim_backend/models/context_models.py View File

82
     """
82
     """
83
     Just some user infos
83
     Just some user infos
84
     """
84
     """
85
-    def __init__(self, timezone: str, public_name: str) -> None:
85
+    def __init__(self, timezone: str, public_name: str, lang: str) -> None:
86
         self.timezone = timezone
86
         self.timezone = timezone
87
         self.public_name = public_name
87
         self.public_name = public_name
88
+        self.lang = lang
88
 
89
 
89
 
90
 
90
 class UserProfile(object):
91
 class UserProfile(object):
106
             public_name: str = None,
107
             public_name: str = None,
107
             timezone: str = None,
108
             timezone: str = None,
108
             profile: str = None,
109
             profile: str = None,
110
+            lang: str = None,
109
             email_notification: bool = True,
111
             email_notification: bool = True,
110
     ) -> None:
112
     ) -> None:
111
         self.email = email
113
         self.email = email
114
         self.password = password or password_generator()
116
         self.password = password or password_generator()
115
         self.public_name = public_name or None
117
         self.public_name = public_name or None
116
         self.timezone = timezone or ''
118
         self.timezone = timezone or ''
119
+        self.lang = lang or None
117
         self.profile = profile or Group.TIM_USER_GROUPNAME
120
         self.profile = profile or Group.TIM_USER_GROUPNAME
118
         self.email_notification = email_notification
121
         self.email_notification = email_notification
119
 
122
 
412
         return self.user.timezone
415
         return self.user.timezone
413
 
416
 
414
     @property
417
     @property
418
+    def lang(self) -> str:
419
+        return self.user.lang
420
+
421
+    @property
415
     def profile(self) -> Profile:
422
     def profile(self) -> Profile:
416
         return self.user.profile.name
423
         return self.user.profile.name
417
 
424
 

+ 2 - 0
backend/tracim_backend/tests/functional/test_session.py View File

160
         assert res.json_body['profile'] == 'administrators'
160
         assert res.json_body['profile'] == 'administrators'
161
         assert res.json_body['caldav_url'] is None
161
         assert res.json_body['caldav_url'] is None
162
         assert res.json_body['avatar_url'] is None
162
         assert res.json_body['avatar_url'] is None
163
+        assert res.json_body['lang'] is None
163
 
164
 
164
     def test_api__try_whoami_enpoint__err_401__user_is_not_active(self):
165
     def test_api__try_whoami_enpoint__err_401__user_is_not_active(self):
165
         dbsession = get_tm_session(self.session_factory, transaction.manager)
166
         dbsession = get_tm_session(self.session_factory, transaction.manager)
183
             name='bob',
184
             name='bob',
184
             groups=groups,
185
             groups=groups,
185
             timezone='Europe/Paris',
186
             timezone='Europe/Paris',
187
+            lang='en',
186
             do_save=True,
188
             do_save=True,
187
             do_notify=False,
189
             do_notify=False,
188
         )
190
         )

+ 81 - 1
backend/tracim_backend/tests/functional/test_user.py View File

76
             name='bob',
76
             name='bob',
77
             groups=groups,
77
             groups=groups,
78
             timezone='Europe/Paris',
78
             timezone='Europe/Paris',
79
+            lang='fr',
79
             do_save=True,
80
             do_save=True,
80
             do_notify=False,
81
             do_notify=False,
81
         )
82
         )
200
             name='bob',
201
             name='bob',
201
             groups=groups,
202
             groups=groups,
202
             timezone='Europe/Paris',
203
             timezone='Europe/Paris',
204
+            lang='fr',
203
             do_save=True,
205
             do_save=True,
204
             do_notify=False,
206
             do_notify=False,
205
         )
207
         )
291
             name='bob',
293
             name='bob',
292
             groups=groups,
294
             groups=groups,
293
             timezone='Europe/Paris',
295
             timezone='Europe/Paris',
296
+            lang='fr',
294
             do_save=True,
297
             do_save=True,
295
             do_notify=False,
298
             do_notify=False,
296
         )
299
         )
416
             name='bob',
419
             name='bob',
417
             groups=groups,
420
             groups=groups,
418
             timezone='Europe/Paris',
421
             timezone='Europe/Paris',
422
+            lang='fr',
419
             do_save=True,
423
             do_save=True,
420
             do_notify=False,
424
             do_notify=False,
421
         )
425
         )
704
             name='bob',
708
             name='bob',
705
             groups=groups,
709
             groups=groups,
706
             timezone='Europe/Paris',
710
             timezone='Europe/Paris',
711
+            lang='fr',
707
             do_save=True,
712
             do_save=True,
708
             do_notify=False,
713
             do_notify=False,
709
         )
714
         )
816
             name='bob',
821
             name='bob',
817
             groups=groups,
822
             groups=groups,
818
             timezone='Europe/Paris',
823
             timezone='Europe/Paris',
824
+            lang='fr',
819
             do_save=True,
825
             do_save=True,
820
             do_notify=False,
826
             do_notify=False,
821
         )
827
         )
939
             name='bob',
945
             name='bob',
940
             groups=groups,
946
             groups=groups,
941
             timezone='Europe/Paris',
947
             timezone='Europe/Paris',
948
+            lang='fr',
942
             do_save=True,
949
             do_save=True,
943
             do_notify=False,
950
             do_notify=False,
944
         )
951
         )
1152
             name='bob',
1159
             name='bob',
1153
             groups=groups,
1160
             groups=groups,
1154
             timezone='Europe/Paris',
1161
             timezone='Europe/Paris',
1162
+            lang='fr',
1155
             do_save=True,
1163
             do_save=True,
1156
             do_notify=False,
1164
             do_notify=False,
1157
         )
1165
         )
1233
             name='bob',
1241
             name='bob',
1234
             groups=groups,
1242
             groups=groups,
1235
             timezone='Europe/Paris',
1243
             timezone='Europe/Paris',
1244
+            lang='fr',
1236
             do_save=True,
1245
             do_save=True,
1237
             do_notify=False,
1246
             do_notify=False,
1238
         )
1247
         )
1314
             name='bob',
1323
             name='bob',
1315
             groups=groups,
1324
             groups=groups,
1316
             timezone='Europe/Paris',
1325
             timezone='Europe/Paris',
1326
+            lang='fr',
1317
             do_save=True,
1327
             do_save=True,
1318
             do_notify=False,
1328
             do_notify=False,
1319
         )
1329
         )
1413
             name='bob',
1423
             name='bob',
1414
             groups=groups,
1424
             groups=groups,
1415
             timezone='Europe/Paris',
1425
             timezone='Europe/Paris',
1426
+            lang='fr',
1416
             do_save=True,
1427
             do_save=True,
1417
             do_notify=False,
1428
             do_notify=False,
1418
         )
1429
         )
1494
             name='bob',
1505
             name='bob',
1495
             groups=groups,
1506
             groups=groups,
1496
             timezone='Europe/Paris',
1507
             timezone='Europe/Paris',
1508
+            lang='fr',
1497
             do_save=True,
1509
             do_save=True,
1498
             do_notify=False,
1510
             do_notify=False,
1499
         )
1511
         )
1611
             name='bob',
1623
             name='bob',
1612
             groups=groups,
1624
             groups=groups,
1613
             timezone='Europe/Paris',
1625
             timezone='Europe/Paris',
1626
+            lang='fr',
1614
             do_save=True,
1627
             do_save=True,
1615
             do_notify=False,
1628
             do_notify=False,
1616
         )
1629
         )
1720
             name='bob',
1733
             name='bob',
1721
             groups=groups,
1734
             groups=groups,
1722
             timezone='Europe/Paris',
1735
             timezone='Europe/Paris',
1736
+            lang='fr',
1723
             do_save=True,
1737
             do_save=True,
1724
             do_notify=False,
1738
             do_notify=False,
1725
         )
1739
         )
1801
             name='bob',
1815
             name='bob',
1802
             groups=groups,
1816
             groups=groups,
1803
             timezone='Europe/Paris',
1817
             timezone='Europe/Paris',
1818
+            lang='fr',
1804
             do_save=True,
1819
             do_save=True,
1805
             do_notify=False,
1820
             do_notify=False,
1806
         )
1821
         )
1883
             name='bob',
1898
             name='bob',
1884
             groups=groups,
1899
             groups=groups,
1885
             timezone='Europe/Paris',
1900
             timezone='Europe/Paris',
1901
+            lang='fr',
1886
             do_save=True,
1902
             do_save=True,
1887
             do_notify=False,
1903
             do_notify=False,
1888
         )
1904
         )
1978
             name='bob',
1994
             name='bob',
1979
             groups=groups,
1995
             groups=groups,
1980
             timezone='Europe/Paris',
1996
             timezone='Europe/Paris',
1997
+            lang='fr',
1981
             do_save=True,
1998
             do_save=True,
1982
             do_notify=False,
1999
             do_notify=False,
1983
         )
2000
         )
2122
             name='bob',
2139
             name='bob',
2123
             groups=groups,
2140
             groups=groups,
2124
             timezone='Europe/Paris',
2141
             timezone='Europe/Paris',
2142
+            lang='fr',
2125
             do_save=True,
2143
             do_save=True,
2126
             do_notify=False,
2144
             do_notify=False,
2127
         )
2145
         )
2219
             name='bob',
2237
             name='bob',
2220
             groups=groups,
2238
             groups=groups,
2221
             timezone='Europe/Paris',
2239
             timezone='Europe/Paris',
2240
+            lang='fr',
2222
             do_save=True,
2241
             do_save=True,
2223
             do_notify=False,
2242
             do_notify=False,
2224
         )
2243
         )
2316
             name='bob',
2335
             name='bob',
2317
             groups=groups,
2336
             groups=groups,
2318
             timezone='Europe/Paris',
2337
             timezone='Europe/Paris',
2338
+            lang='fr',
2319
             do_save=True,
2339
             do_save=True,
2320
             do_notify=False,
2340
             do_notify=False,
2321
         )
2341
         )
2496
             name='bob',
2516
             name='bob',
2497
             groups=groups,
2517
             groups=groups,
2498
             timezone='Europe/Paris',
2518
             timezone='Europe/Paris',
2519
+            lang='fr',
2499
             do_save=True,
2520
             do_save=True,
2500
             do_notify=False,
2521
             do_notify=False,
2501
         )
2522
         )
2523
         assert res['public_name'] == 'bob'
2544
         assert res['public_name'] == 'bob'
2524
         assert res['timezone'] == 'Europe/Paris'
2545
         assert res['timezone'] == 'Europe/Paris'
2525
         assert res['is_deleted'] is False
2546
         assert res['is_deleted'] is False
2547
+        assert res['lang'] == 'fr'
2526
 
2548
 
2527
     def test_api__get_user__ok_200__user_itself(self):
2549
     def test_api__get_user__ok_200__user_itself(self):
2528
         dbsession = get_tm_session(self.session_factory, transaction.manager)
2550
         dbsession = get_tm_session(self.session_factory, transaction.manager)
2546
             name='bob',
2568
             name='bob',
2547
             groups=groups,
2569
             groups=groups,
2548
             timezone='Europe/Paris',
2570
             timezone='Europe/Paris',
2571
+            lang='fr',
2549
             do_save=True,
2572
             do_save=True,
2550
             do_notify=False,
2573
             do_notify=False,
2551
         )
2574
         )
2605
             name='bob2',
2628
             name='bob2',
2606
             groups=groups,
2629
             groups=groups,
2607
             timezone='Europe/Paris',
2630
             timezone='Europe/Paris',
2631
+            lang='fr',
2608
             do_save=True,
2632
             do_save=True,
2609
             do_notify=False,
2633
             do_notify=False,
2610
         )
2634
         )
2638
             'password': 'mysuperpassword',
2662
             'password': 'mysuperpassword',
2639
             'profile': 'users',
2663
             'profile': 'users',
2640
             'timezone': 'Europe/Paris',
2664
             'timezone': 'Europe/Paris',
2665
+            'lang': 'fr',
2641
             'public_name': 'test user',
2666
             'public_name': 'test user',
2642
             'email_notification': False,
2667
             'email_notification': False,
2643
         }
2668
         }
2655
         assert res['email'] == 'test@test.test'
2680
         assert res['email'] == 'test@test.test'
2656
         assert res['public_name'] == 'test user'
2681
         assert res['public_name'] == 'test user'
2657
         assert res['timezone'] == 'Europe/Paris'
2682
         assert res['timezone'] == 'Europe/Paris'
2658
-
2683
+        assert res['lang'] == 'fr'
2659
         dbsession = get_tm_session(self.session_factory, transaction.manager)
2684
         dbsession = get_tm_session(self.session_factory, transaction.manager)
2660
         admin = dbsession.query(models.User) \
2685
         admin = dbsession.query(models.User) \
2661
             .filter(models.User.email == 'admin@admin.admin') \
2686
             .filter(models.User.email == 'admin@admin.admin') \
2695
         assert res['email'] == 'test@test.test'
2720
         assert res['email'] == 'test@test.test'
2696
         assert res['public_name'] == 'test'
2721
         assert res['public_name'] == 'test'
2697
         assert res['timezone'] == ''
2722
         assert res['timezone'] == ''
2723
+        assert res['lang'] is None
2698
 
2724
 
2699
         dbsession = get_tm_session(self.session_factory, transaction.manager)
2725
         dbsession = get_tm_session(self.session_factory, transaction.manager)
2700
         admin = dbsession.query(models.User) \
2726
         admin = dbsession.query(models.User) \
2731
             name='bob',
2757
             name='bob',
2732
             groups=groups,
2758
             groups=groups,
2733
             timezone='Europe/Paris',
2759
             timezone='Europe/Paris',
2760
+            lang='fr',
2734
             do_save=True,
2761
             do_save=True,
2735
             do_notify=False,
2762
             do_notify=False,
2736
         )
2763
         )
2748
             'password': 'mysuperpassword',
2775
             'password': 'mysuperpassword',
2749
             'profile': 'users',
2776
             'profile': 'users',
2750
             'timezone': 'Europe/Paris',
2777
             'timezone': 'Europe/Paris',
2778
+            'lang': 'fr',
2751
             'public_name': 'test user',
2779
             'public_name': 'test user',
2752
             'email_notification': False,
2780
             'email_notification': False,
2753
         }
2781
         }
2779
             name='bob',
2807
             name='bob',
2780
             groups=groups,
2808
             groups=groups,
2781
             timezone='Europe/Paris',
2809
             timezone='Europe/Paris',
2810
+            lang='fr',
2782
             do_save=True,
2811
             do_save=True,
2783
             do_notify=False,
2812
             do_notify=False,
2784
         )
2813
         )
2797
             'profile': 'users',
2826
             'profile': 'users',
2798
             'timezone': 'Europe/Paris',
2827
             'timezone': 'Europe/Paris',
2799
             'public_name': 'test user',
2828
             'public_name': 'test user',
2829
+            'lang': 'fr',
2800
             'email_notification': False,
2830
             'email_notification': False,
2801
         }
2831
         }
2802
         res = self.testapp.post_json(
2832
         res = self.testapp.post_json(
2827
             'profile': 'users',
2857
             'profile': 'users',
2828
             'timezone': 'Europe/Paris',
2858
             'timezone': 'Europe/Paris',
2829
             'public_name': 'test user',
2859
             'public_name': 'test user',
2860
+            'lang': 'fr',
2830
             'email_notification': True,
2861
             'email_notification': True,
2831
         }
2862
         }
2832
         res = self.testapp.post_json(
2863
         res = self.testapp.post_json(
2843
         assert res['email'] == 'test@test.test'
2874
         assert res['email'] == 'test@test.test'
2844
         assert res['public_name'] == 'test user'
2875
         assert res['public_name'] == 'test user'
2845
         assert res['timezone'] == 'Europe/Paris'
2876
         assert res['timezone'] == 'Europe/Paris'
2877
+        assert res['lang'] == 'fr'
2846
 
2878
 
2847
         dbsession = get_tm_session(self.session_factory, transaction.manager)
2879
         dbsession = get_tm_session(self.session_factory, transaction.manager)
2848
         admin = dbsession.query(models.User) \
2880
         admin = dbsession.query(models.User) \
2896
         assert res['email'] == 'test@test.test'
2928
         assert res['email'] == 'test@test.test'
2897
         assert res['public_name'] == 'test'
2929
         assert res['public_name'] == 'test'
2898
         assert res['timezone'] == ''
2930
         assert res['timezone'] == ''
2931
+        assert res['lang'] == None
2899
 
2932
 
2900
         dbsession = get_tm_session(self.session_factory, transaction.manager)
2933
         dbsession = get_tm_session(self.session_factory, transaction.manager)
2901
         admin = dbsession.query(models.User) \
2934
         admin = dbsession.query(models.User) \
2944
             name='bob',
2977
             name='bob',
2945
             groups=groups,
2978
             groups=groups,
2946
             timezone='Europe/Paris',
2979
             timezone='Europe/Paris',
2980
+            lang='fr',
2947
             do_save=True,
2981
             do_save=True,
2948
             do_notify=False,
2982
             do_notify=False,
2949
         )
2983
         )
2998
             name='bob',
3032
             name='bob',
2999
             groups=groups,
3033
             groups=groups,
3000
             timezone='Europe/Paris',
3034
             timezone='Europe/Paris',
3035
+            lang='fr',
3001
             do_save=True,
3036
             do_save=True,
3002
             do_notify=False,
3037
             do_notify=False,
3003
         )
3038
         )
3048
             name='bob',
3083
             name='bob',
3049
             groups=groups,
3084
             groups=groups,
3050
             timezone='Europe/Paris',
3085
             timezone='Europe/Paris',
3086
+            lang='fr',
3051
             do_save=True,
3087
             do_save=True,
3052
             do_notify=False,
3088
             do_notify=False,
3053
         )
3089
         )
3097
             name='bob',
3133
             name='bob',
3098
             groups=groups,
3134
             groups=groups,
3099
             timezone='Europe/Paris',
3135
             timezone='Europe/Paris',
3136
+            lang='fr',
3100
             do_save=True,
3137
             do_save=True,
3101
             do_notify=False,
3138
             do_notify=False,
3102
         )
3139
         )
3106
             name='bob2',
3143
             name='bob2',
3107
             groups=groups,
3144
             groups=groups,
3108
             timezone='Europe/Paris',
3145
             timezone='Europe/Paris',
3146
+            lang='fr',
3109
             do_save=True,
3147
             do_save=True,
3110
             do_notify=False,
3148
             do_notify=False,
3111
         )
3149
         )
3161
             name='bob',
3199
             name='bob',
3162
             groups=groups,
3200
             groups=groups,
3163
             timezone='Europe/Paris',
3201
             timezone='Europe/Paris',
3202
+            lang='fr',
3164
             do_save=True,
3203
             do_save=True,
3165
             do_notify=False,
3204
             do_notify=False,
3166
         )
3205
         )
3170
             name='bob2',
3209
             name='bob2',
3171
             groups=groups,
3210
             groups=groups,
3172
             timezone='Europe/Paris',
3211
             timezone='Europe/Paris',
3212
+            lang='fr',
3173
             do_save=True,
3213
             do_save=True,
3174
             do_notify=False,
3214
             do_notify=False,
3175
         )
3215
         )
3225
             name='bob',
3265
             name='bob',
3226
             groups=groups,
3266
             groups=groups,
3227
             timezone='Europe/Paris',
3267
             timezone='Europe/Paris',
3268
+            lang='fr',
3228
             do_save=True,
3269
             do_save=True,
3229
             do_notify=False,
3270
             do_notify=False,
3230
         )
3271
         )
3234
             name='bob2',
3275
             name='bob2',
3235
             groups=groups,
3276
             groups=groups,
3236
             timezone='Europe/Paris',
3277
             timezone='Europe/Paris',
3278
+            lang='fr',
3237
             do_save=True,
3279
             do_save=True,
3238
             do_notify=False,
3280
             do_notify=False,
3239
         )
3281
         )
3279
             name='bob',
3321
             name='bob',
3280
             groups=groups,
3322
             groups=groups,
3281
             timezone='Europe/Paris',
3323
             timezone='Europe/Paris',
3324
+            lang='fr',
3282
             do_save=True,
3325
             do_save=True,
3283
             do_notify=False,
3326
             do_notify=False,
3284
         )
3327
         )
3288
             name='bob2',
3331
             name='bob2',
3289
             groups=groups,
3332
             groups=groups,
3290
             timezone='Europe/Paris',
3333
             timezone='Europe/Paris',
3334
+            lang='fr',
3291
             do_save=True,
3335
             do_save=True,
3292
             do_notify=False,
3336
             do_notify=False,
3293
         )
3337
         )
3297
             name='bob3',
3341
             name='bob3',
3298
             groups=groups,
3342
             groups=groups,
3299
             timezone='Europe/Paris',
3343
             timezone='Europe/Paris',
3344
+            lang='fr',
3300
             do_save=True,
3345
             do_save=True,
3301
             do_notify=False,
3346
             do_notify=False,
3302
         )
3347
         )
3382
             name='bob',
3427
             name='bob',
3383
             groups=groups,
3428
             groups=groups,
3384
             timezone='Europe/Paris',
3429
             timezone='Europe/Paris',
3430
+            lang='fr',
3385
             do_save=True,
3431
             do_save=True,
3386
             do_notify=False,
3432
             do_notify=False,
3387
         )
3433
         )
3444
             name='bob',
3490
             name='bob',
3445
             groups=groups,
3491
             groups=groups,
3446
             timezone='Europe/Paris',
3492
             timezone='Europe/Paris',
3493
+            lang='fr',
3447
             do_save=True,
3494
             do_save=True,
3448
             do_notify=False,
3495
             do_notify=False,
3449
         )
3496
         )
3506
             name='bob',
3553
             name='bob',
3507
             groups=groups,
3554
             groups=groups,
3508
             timezone='Europe/Paris',
3555
             timezone='Europe/Paris',
3556
+            lang='fr',
3509
             do_save=True,
3557
             do_save=True,
3510
             do_notify=False,
3558
             do_notify=False,
3511
         )
3559
         )
3568
             name='bob',
3616
             name='bob',
3569
             groups=groups,
3617
             groups=groups,
3570
             timezone='Europe/Paris',
3618
             timezone='Europe/Paris',
3619
+            lang='fr',
3571
             do_save=True,
3620
             do_save=True,
3572
             do_notify=False,
3621
             do_notify=False,
3573
         )
3622
         )
3630
             name='bob',
3679
             name='bob',
3631
             groups=groups,
3680
             groups=groups,
3632
             timezone='Europe/Paris',
3681
             timezone='Europe/Paris',
3682
+            lang='fr',
3633
             do_save=True,
3683
             do_save=True,
3634
             do_notify=False,
3684
             do_notify=False,
3635
         )
3685
         )
3699
             name='bob',
3749
             name='bob',
3700
             groups=groups,
3750
             groups=groups,
3701
             timezone='Europe/Paris',
3751
             timezone='Europe/Paris',
3752
+            lang='fr',
3702
             do_save=True,
3753
             do_save=True,
3703
             do_notify=False,
3754
             do_notify=False,
3704
         )
3755
         )
3708
             name='bob2',
3759
             name='bob2',
3709
             groups=groups,
3760
             groups=groups,
3710
             timezone='Europe/Paris',
3761
             timezone='Europe/Paris',
3762
+            lang='fr',
3711
             do_save=True,
3763
             do_save=True,
3712
             do_notify=False,
3764
             do_notify=False,
3713
         )
3765
         )
3764
             name='bob',
3816
             name='bob',
3765
             groups=groups,
3817
             groups=groups,
3766
             timezone='Europe/Paris',
3818
             timezone='Europe/Paris',
3819
+            lang='fr',
3767
             do_save=True,
3820
             do_save=True,
3768
             do_notify=False,
3821
             do_notify=False,
3769
         )
3822
         )
3826
             name='bob',
3879
             name='bob',
3827
             groups=groups,
3880
             groups=groups,
3828
             timezone='Europe/Paris',
3881
             timezone='Europe/Paris',
3882
+            lang='fr',
3829
             do_save=True,
3883
             do_save=True,
3830
             do_notify=False,
3884
             do_notify=False,
3831
         )
3885
         )
3888
             name='bob',
3942
             name='bob',
3889
             groups=groups,
3943
             groups=groups,
3890
             timezone='Europe/Paris',
3944
             timezone='Europe/Paris',
3945
+            lang='fr',
3891
             do_save=True,
3946
             do_save=True,
3892
             do_notify=False,
3947
             do_notify=False,
3893
         )
3948
         )
3952
             name='bob',
4007
             name='bob',
3953
             groups=groups,
4008
             groups=groups,
3954
             timezone='Europe/Paris',
4009
             timezone='Europe/Paris',
4010
+            lang='fr',
3955
             do_save=True,
4011
             do_save=True,
3956
             do_notify=False,
4012
             do_notify=False,
3957
         )
4013
         )
4013
             password='pass',
4069
             password='pass',
4014
             name='bob',
4070
             name='bob',
4015
             groups=groups,
4071
             groups=groups,
4072
+            lang='fr',
4016
             timezone='Europe/Paris',
4073
             timezone='Europe/Paris',
4017
             do_save=True,
4074
             do_save=True,
4018
             do_notify=False,
4075
             do_notify=False,
4023
             name='bob2',
4080
             name='bob2',
4024
             groups=groups,
4081
             groups=groups,
4025
             timezone='Europe/Paris',
4082
             timezone='Europe/Paris',
4083
+            lang='fr',
4026
             do_save=True,
4084
             do_save=True,
4027
             do_notify=False,
4085
             do_notify=False,
4028
         )
4086
         )
4079
             name='bob',
4137
             name='bob',
4080
             groups=groups,
4138
             groups=groups,
4081
             timezone='Europe/Paris',
4139
             timezone='Europe/Paris',
4140
+            lang='fr',
4082
             do_save=True,
4141
             do_save=True,
4083
             do_notify=False,
4142
             do_notify=False,
4084
         )
4143
         )
4102
         assert res['user_id'] == user_id
4161
         assert res['user_id'] == user_id
4103
         assert res['public_name'] == 'bob'
4162
         assert res['public_name'] == 'bob'
4104
         assert res['timezone'] == 'Europe/Paris'
4163
         assert res['timezone'] == 'Europe/Paris'
4164
+        assert res['lang'] == 'fr'
4105
         # Set params
4165
         # Set params
4106
         params = {
4166
         params = {
4107
             'public_name': 'updated',
4167
             'public_name': 'updated',
4108
             'timezone': 'Europe/London',
4168
             'timezone': 'Europe/London',
4169
+            'lang': 'en',
4109
         }
4170
         }
4110
         self.testapp.put_json(
4171
         self.testapp.put_json(
4111
             '/api/v2/users/{}'.format(user_id),
4172
             '/api/v2/users/{}'.format(user_id),
4121
         assert res['user_id'] == user_id
4182
         assert res['user_id'] == user_id
4122
         assert res['public_name'] == 'updated'
4183
         assert res['public_name'] == 'updated'
4123
         assert res['timezone'] == 'Europe/London'
4184
         assert res['timezone'] == 'Europe/London'
4185
+        assert res['lang'] == 'en'
4124
 
4186
 
4125
     def test_api__set_user_info__ok_200__user_itself(self):
4187
     def test_api__set_user_info__ok_200__user_itself(self):
4126
         dbsession = get_tm_session(self.session_factory, transaction.manager)
4188
         dbsession = get_tm_session(self.session_factory, transaction.manager)
4144
             name='bob',
4206
             name='bob',
4145
             groups=groups,
4207
             groups=groups,
4146
             timezone='Europe/Paris',
4208
             timezone='Europe/Paris',
4209
+            lang='fr',
4147
             do_save=True,
4210
             do_save=True,
4148
             do_notify=False,
4211
             do_notify=False,
4149
         )
4212
         )
4167
         assert res['user_id'] == user_id
4230
         assert res['user_id'] == user_id
4168
         assert res['public_name'] == 'bob'
4231
         assert res['public_name'] == 'bob'
4169
         assert res['timezone'] == 'Europe/Paris'
4232
         assert res['timezone'] == 'Europe/Paris'
4233
+        assert res['lang'] == 'fr'
4170
         # Set params
4234
         # Set params
4171
         params = {
4235
         params = {
4172
             'public_name': 'updated',
4236
             'public_name': 'updated',
4173
             'timezone': 'Europe/London',
4237
             'timezone': 'Europe/London',
4238
+            'lang' : 'en',
4174
         }
4239
         }
4175
         self.testapp.put_json(
4240
         self.testapp.put_json(
4176
             '/api/v2/users/{}'.format(user_id),
4241
             '/api/v2/users/{}'.format(user_id),
4186
         assert res['user_id'] == user_id
4251
         assert res['user_id'] == user_id
4187
         assert res['public_name'] == 'updated'
4252
         assert res['public_name'] == 'updated'
4188
         assert res['timezone'] == 'Europe/London'
4253
         assert res['timezone'] == 'Europe/London'
4254
+        assert res['lang'] == 'en'
4189
 
4255
 
4190
     def test_api__set_user_email__err_403__other_normal_user(self):
4256
     def test_api__set_user_email__err_403__other_normal_user(self):
4191
         dbsession = get_tm_session(self.session_factory, transaction.manager)
4257
         dbsession = get_tm_session(self.session_factory, transaction.manager)
4209
             name='bob',
4275
             name='bob',
4210
             groups=groups,
4276
             groups=groups,
4211
             timezone='Europe/Paris',
4277
             timezone='Europe/Paris',
4278
+            lang='fr',
4212
             do_save=True,
4279
             do_save=True,
4213
             do_notify=False,
4280
             do_notify=False,
4214
         )
4281
         )
4218
             name='test',
4285
             name='test',
4219
             groups=groups,
4286
             groups=groups,
4220
             timezone='Europe/Paris',
4287
             timezone='Europe/Paris',
4288
+            lang='fr',
4221
             do_save=True,
4289
             do_save=True,
4222
             do_notify=False,
4290
             do_notify=False,
4223
         )
4291
         )
4237
         params = {
4305
         params = {
4238
             'public_name': 'updated',
4306
             'public_name': 'updated',
4239
             'timezone': 'Europe/London',
4307
             'timezone': 'Europe/London',
4308
+            'lang': 'en'
4240
         }
4309
         }
4241
         self.testapp.put_json(
4310
         self.testapp.put_json(
4242
             '/api/v2/users/{}'.format(user_id),
4311
             '/api/v2/users/{}'.format(user_id),
4274
             name='bob',
4343
             name='bob',
4275
             groups=groups,
4344
             groups=groups,
4276
             timezone='Europe/Paris',
4345
             timezone='Europe/Paris',
4346
+            lang='fr',
4277
             do_save=True,
4347
             do_save=True,
4278
             do_notify=False,
4348
             do_notify=False,
4279
         )
4349
         )
4336
             name='bob',
4406
             name='bob',
4337
             groups=groups,
4407
             groups=groups,
4338
             timezone='Europe/Paris',
4408
             timezone='Europe/Paris',
4409
+            lang='fr',
4339
             do_save=True,
4410
             do_save=True,
4340
             do_notify=False,
4411
             do_notify=False,
4341
         )
4412
         )
4398
             name='bob',
4469
             name='bob',
4399
             groups=groups,
4470
             groups=groups,
4400
             timezone='Europe/Paris',
4471
             timezone='Europe/Paris',
4472
+            lang='fr',
4401
             do_save=True,
4473
             do_save=True,
4402
             do_notify=False,
4474
             do_notify=False,
4403
         )
4475
         )
4407
             name='test',
4479
             name='test',
4408
             groups=groups,
4480
             groups=groups,
4409
             timezone='Europe/Paris',
4481
             timezone='Europe/Paris',
4482
+            lang='fr',
4410
             do_save=True,
4483
             do_save=True,
4411
             do_notify=False,
4484
             do_notify=False,
4412
         )
4485
         )
4463
             name='bob',
4536
             name='bob',
4464
             groups=groups,
4537
             groups=groups,
4465
             timezone='Europe/Paris',
4538
             timezone='Europe/Paris',
4539
+            lang='fr',
4466
             do_save=True,
4540
             do_save=True,
4467
             do_notify=False,
4541
             do_notify=False,
4468
         )
4542
         )
4521
             name='bob',
4595
             name='bob',
4522
             groups=groups,
4596
             groups=groups,
4523
             timezone='Europe/Paris',
4597
             timezone='Europe/Paris',
4598
+            lang='fr',
4524
             do_save=True,
4599
             do_save=True,
4525
             do_notify=False,
4600
             do_notify=False,
4526
         )
4601
         )
4579
             name='bob',
4654
             name='bob',
4580
             groups=groups,
4655
             groups=groups,
4581
             timezone='Europe/Paris',
4656
             timezone='Europe/Paris',
4657
+            lang='fr',
4582
             do_save=True,
4658
             do_save=True,
4583
             do_notify=False,
4659
             do_notify=False,
4584
         )
4660
         )
4588
             name='test2',
4664
             name='test2',
4589
             groups=groups,
4665
             groups=groups,
4590
             timezone='Europe/Paris',
4666
             timezone='Europe/Paris',
4667
+            lang='fr',
4591
             do_save=True,
4668
             do_save=True,
4592
             do_notify=False,
4669
             do_notify=False,
4593
         )
4670
         )
4631
             name='bob',
4708
             name='bob',
4632
             groups=groups,
4709
             groups=groups,
4633
             timezone='Europe/Paris',
4710
             timezone='Europe/Paris',
4711
+            lang='fr',
4634
             do_save=True,
4712
             do_save=True,
4635
             do_notify=False,
4713
             do_notify=False,
4636
         )
4714
         )
4640
             name='test2',
4718
             name='test2',
4641
             groups=groups,
4719
             groups=groups,
4642
             timezone='Europe/Paris',
4720
             timezone='Europe/Paris',
4721
+            lang='fr',
4643
             do_save=True,
4722
             do_save=True,
4644
             do_notify=False,
4723
             do_notify=False,
4645
         )
4724
         )
4683
             name='bob',
4762
             name='bob',
4684
             groups=groups,
4763
             groups=groups,
4685
             timezone='Europe/Paris',
4764
             timezone='Europe/Paris',
4765
+            lang='fr',
4686
             do_save=True,
4766
             do_save=True,
4687
             do_notify=False,
4767
             do_notify=False,
4688
         )
4768
         )

+ 2 - 0
backend/tracim_backend/tests/library/test_user_api.py View File

55
             password='pass',
55
             password='pass',
56
             name='bob',
56
             name='bob',
57
             timezone='+2',
57
             timezone='+2',
58
+            lang='en',
58
             do_save=True,
59
             do_save=True,
59
             do_notify=False,
60
             do_notify=False,
60
         )
61
         )
63
         assert u.validate_password('pass')
64
         assert u.validate_password('pass')
64
         assert u.display_name == 'bob'
65
         assert u.display_name == 'bob'
65
         assert u.timezone == '+2'
66
         assert u.timezone == '+2'
67
+        assert u.lang == 'en'
66
 
68
 
67
     def test_unit__user_with_email_exists__ok__nominal_case(self):
69
     def test_unit__user_with_email_exists__ok__nominal_case(self):
68
         api = UserApi(
70
         api = UserApi(

+ 27 - 0
backend/tracim_backend/views/core_api/schemas.py View File

84
     )
84
     )
85
     # TODO - G.M - 17-04-2018 - Restrict timezone values
85
     # TODO - G.M - 17-04-2018 - Restrict timezone values
86
     timezone = marshmallow.fields.String(
86
     timezone = marshmallow.fields.String(
87
+        description="Timezone as tz database format",
87
         example="Europe/Paris",
88
         example="Europe/Paris",
88
     )
89
     )
89
     # TODO - G.M - 17-04-2018 - check this, relative url allowed ?
90
     # TODO - G.M - 17-04-2018 - check this, relative url allowed ?
99
         validate=OneOf(Profile._NAME),
100
         validate=OneOf(Profile._NAME),
100
         example='managers',
101
         example='managers',
101
     )
102
     )
103
+    lang = marshmallow.fields.String(
104
+        description="User langage in iso639 format",
105
+        example='en',
106
+        required=False,
107
+        validate=Length(min=2, max=3),
108
+        allow_none=True,
109
+        default=None,
110
+    )
102
 
111
 
103
     class Meta:
112
     class Meta:
104
         description = 'User account of Tracim'
113
         description = 'User account of Tracim'
138
 
147
 
139
 class UserInfosSchema(marshmallow.Schema):
148
 class UserInfosSchema(marshmallow.Schema):
140
     timezone = marshmallow.fields.String(
149
     timezone = marshmallow.fields.String(
150
+        description="Timezone as tz database format",
141
         example="Europe/Paris",
151
         example="Europe/Paris",
142
         required=True,
152
         required=True,
143
     )
153
     )
145
         example='Suri Cate',
155
         example='Suri Cate',
146
         required=True,
156
         required=True,
147
     )
157
     )
158
+    lang = marshmallow.fields.String(
159
+        description="User langage in iso639 format",
160
+        example='en',
161
+        required=True,
162
+        validate=Length(min=2, max=3),
163
+        allow_none=True,
164
+        default=None,
165
+    )
148
 
166
 
149
     @post_load
167
     @post_load
150
     def create_user_info_object(self, data):
168
     def create_user_info_object(self, data):
179
         default=Group.TIM_USER_GROUPNAME
197
         default=Group.TIM_USER_GROUPNAME
180
     )
198
     )
181
     timezone = marshmallow.fields.String(
199
     timezone = marshmallow.fields.String(
200
+        description="Timezone as tz database format",
182
         example="Europe/Paris",
201
         example="Europe/Paris",
183
         required=False,
202
         required=False,
184
         default=''
203
         default=''
188
         required=False,
207
         required=False,
189
         default=None,
208
         default=None,
190
     )
209
     )
210
+    lang = marshmallow.fields.String(
211
+        description="User langage in iso639 format",
212
+        example='en',
213
+        required=False,
214
+        validate=Length(min=2, max=3),
215
+        allow_none=True,
216
+        default=None,
217
+    )
191
     email_notification = marshmallow.fields.Bool(
218
     email_notification = marshmallow.fields.Bool(
192
         example=True,
219
         example=True,
193
         required=False,
220
         required=False,

+ 2 - 0
backend/tracim_backend/views/core_api/user_controller.py View File

190
             request.candidate_user,
190
             request.candidate_user,
191
             name=hapic_data.body.public_name,
191
             name=hapic_data.body.public_name,
192
             timezone=hapic_data.body.timezone,
192
             timezone=hapic_data.body.timezone,
193
+            lang=hapic_data.body.lang,
193
             do_save=True
194
             do_save=True
194
         )
195
         )
195
         return uapi.get_user_with_context(user)
196
         return uapi.get_user_with_context(user)
219
             email=hapic_data.body.email,
220
             email=hapic_data.body.email,
220
             password=hapic_data.body.password,
221
             password=hapic_data.body.password,
221
             timezone=hapic_data.body.timezone,
222
             timezone=hapic_data.body.timezone,
223
+            lang=hapic_data.body.lang,
222
             name=hapic_data.body.public_name,
224
             name=hapic_data.body.public_name,
223
             do_notify=hapic_data.body.email_notification,
225
             do_notify=hapic_data.body.email_notification,
224
             groups=groups,
226
             groups=groups,