Browse Source

Merge pull request #10 from tracim/fix/611_reenable_email_new_user_notification_with_password

Bastien Sevajol 6 years ago
parent
commit
1e73e4afc0
No account linked to committer's email

+ 67 - 0
backend/tests_configs.ini View File

63
 email.notification.smtp.port = 1025
63
 email.notification.smtp.port = 1025
64
 email.notification.smtp.user = test_user
64
 email.notification.smtp.user = test_user
65
 email.notification.smtp.password = just_a_password
65
 email.notification.smtp.password = just_a_password
66
+
67
+[functional_test]
68
+sqlalchemy.url = sqlite:///tracim_test.sqlite
69
+depot_storage_name = test
70
+depot_storage_dir = /tmp/test/depot
71
+user.auth_token.validity = 604800
72
+preview_cache_dir = /tmp/test/preview_cache
73
+preview.jpg.restricted_dims = True
74
+email.notification.activated = false
75
+
76
+[functional_test_no_db]
77
+sqlalchemy.url = sqlite://
78
+depot_storage_name = test
79
+depot_storage_dir = /tmp/test/depot
80
+user.auth_token.validity = 604800
81
+preview_cache_dir = /tmp/test/preview_cache
82
+preview.jpg.restricted_dims = True
83
+email.notification.activated = false
84
+
85
+[functional_test_with_mail_test_sync]
86
+sqlalchemy.url = sqlite:///tracim_test.sqlite
87
+depot_storage_name = test
88
+depot_storage_dir = /tmp/test/depot
89
+user.auth_token.validity = 604800
90
+preview_cache_dir = /tmp/test/preview_cache
91
+preview.jpg.restricted_dims = True
92
+email.notification.activated = true
93
+email.notification.from.email = test_user_from+{user_id}@localhost
94
+email.notification.from.default_label = Tracim Notifications
95
+email.notification.reply_to.email = test_user_reply+{content_id}@localhost
96
+email.notification.references.email = test_user_refs+{content_id}@localhost
97
+email.notification.content_update.template.html = %(here)s/tracim_backend/templates/mail/content_update_body_html.mak
98
+email.notification.content_update.template.text = %(here)s/tracim_backend/templates/mail/content_update_body_text.mak
99
+email.notification.created_account.template.html = %(here)s/tracim_backend/templates/mail/created_account_body_html.mak
100
+email.notification.created_account.template.text = %(here)s/tracim_backend/templates/mail/created_account_body_text.mak
101
+email.notification.content_update.subject = [{website_title}] [{workspace_label}] {content_label} ({content_status_label})
102
+email.notification.created_account.subject = [{website_title}] Created account
103
+email.notification.processing_mode = sync
104
+email.notification.smtp.server = 127.0.0.1
105
+email.notification.smtp.port = 1025
106
+email.notification.smtp.user = test_user
107
+email.notification.smtp.password = just_a_password
108
+
109
+
110
+[functional_test_with_mail_test_async]
111
+sqlalchemy.url = sqlite:///tracim_test.sqlite
112
+depot_storage_name = test
113
+depot_storage_dir = /tmp/test/depot
114
+user.auth_token.validity = 604800
115
+preview_cache_dir = /tmp/test/preview_cache
116
+preview.jpg.restricted_dims = True
117
+email.notification.activated = true
118
+email.notification.from.email = test_user_from+{user_id}@localhost
119
+email.notification.from.default_label = Tracim Notifications
120
+email.notification.reply_to.email = test_user_reply+{content_id}@localhost
121
+email.notification.references.email = test_user_refs+{content_id}@localhost
122
+email.notification.content_update.template.html = %(here)s/tracim_backend/templates/mail/content_update_body_html.mak
123
+email.notification.content_update.template.text = %(here)s/tracim_backend/templates/mail/content_update_body_text.mak
124
+email.notification.created_account.template.html = %(here)s/tracim_backend/templates/mail/created_account_body_html.mak
125
+email.notification.created_account.template.text = %(here)s/tracim_backend/templates/mail/created_account_body_text.mak
126
+email.notification.content_update.subject = [{website_title}] [{workspace_label}] {content_label} ({content_status_label})
127
+email.notification.created_account.subject = [{website_title}] Created account
128
+email.notification.processing_mode = async
129
+email.notification.smtp.server = 127.0.0.1
130
+email.notification.smtp.port = 1025
131
+email.notification.smtp.user = test_user
132
+email.notification.smtp.password = just_a_password

+ 3 - 1
backend/tracim_backend/config.py View File

161
 
161
 
162
         self.EMAIL_NOTIFICATION_FROM_EMAIL = settings.get(
162
         self.EMAIL_NOTIFICATION_FROM_EMAIL = settings.get(
163
             'email.notification.from.email',
163
             'email.notification.from.email',
164
+            'noreply+{user_id}@trac.im'
164
         )
165
         )
165
         self.EMAIL_NOTIFICATION_FROM_DEFAULT_LABEL = settings.get(
166
         self.EMAIL_NOTIFICATION_FROM_DEFAULT_LABEL = settings.get(
166
-            'email.notification.from.default_label'
167
+            'email.notification.from.default_label',
168
+            'Tracim Notifications'
167
         )
169
         )
168
         self.EMAIL_NOTIFICATION_REPLY_TO_EMAIL = settings.get(
170
         self.EMAIL_NOTIFICATION_REPLY_TO_EMAIL = settings.get(
169
             'email.notification.reply_to.email',
171
             'email.notification.reply_to.email',

+ 24 - 0
backend/tracim_backend/lib/utils/utils.py View File

1
 # -*- coding: utf-8 -*-
1
 # -*- coding: utf-8 -*-
2
 import datetime
2
 import datetime
3
+import random
4
+import string
3
 from redis import Redis
5
 from redis import Redis
4
 from rq import Queue
6
 from rq import Queue
5
 
7
 
72
     # webdav utils, it may cause trouble. So, it should be replaced to
74
     # webdav utils, it may cause trouble. So, it should be replaced to
73
     # a character which will not change in bdd.
75
     # a character which will not change in bdd.
74
     return datetime.datetime.now().isoformat().replace(':', '.')
76
     return datetime.datetime.now().isoformat().replace(':', '.')
77
+
78
+# INFO - G.M - 2018-08-02 - Simple password generator, inspired by
79
+# https://gist.github.com/23maverick23/4131896
80
+
81
+
82
+ALLOWED_AUTOGEN_PASSWORD_CHAR = string.ascii_letters + \
83
+                                string.digits + \
84
+                                string.punctuation
85
+
86
+DEFAULT_PASSWORD_GEN_CHAR_LENGTH = 12
87
+
88
+
89
+def password_generator(
90
+        length: int=DEFAULT_PASSWORD_GEN_CHAR_LENGTH,
91
+        chars: str=ALLOWED_AUTOGEN_PASSWORD_CHAR
92
+) -> str:
93
+    """
94
+    :param length: length of the new password
95
+    :param chars: characters allowed
96
+    :return: password as string
97
+    """
98
+    return ''.join(random.choice(chars) for char_number in range(length))

+ 8 - 11
backend/tracim_backend/tests/__init__.py View File

68
 class FunctionalTest(unittest.TestCase):
68
 class FunctionalTest(unittest.TestCase):
69
 
69
 
70
     fixtures = [BaseFixture]
70
     fixtures = [BaseFixture]
71
-    sqlalchemy_url = 'sqlite:///tracim_test.sqlite'
71
+    config_uri = 'tests_configs.ini'
72
+    config_section = 'functional_test'
72
 
73
 
73
     def setUp(self):
74
     def setUp(self):
74
         logger._logger.setLevel('WARNING')
75
         logger._logger.setLevel('WARNING')
76
+
75
         DepotManager._clear()
77
         DepotManager._clear()
76
-        self.settings = {
77
-            'sqlalchemy.url': self.sqlalchemy_url,
78
-            'user.auth_token.validity': '604800',
79
-            'depot_storage_dir': '/tmp/test/depot',
80
-            'depot_storage_name': 'test',
81
-            'preview_cache_dir': '/tmp/test/preview_cache',
82
-            'preview.jpg.restricted_dims': True,
83
-            'email.notification.activated': 'false',
84
-        }
78
+        self.settings = plaster.get_settings(
79
+            self.config_uri,
80
+            self.config_section
81
+        )
85
         hapic.reset_context()
82
         hapic.reset_context()
86
         self.engine = get_engine(self.settings)
83
         self.engine = get_engine(self.settings)
87
         DeclarativeBase.metadata.create_all(self.engine)
84
         DeclarativeBase.metadata.create_all(self.engine)
127
 
124
 
128
 
125
 
129
 class FunctionalTestNoDB(FunctionalTest):
126
 class FunctionalTestNoDB(FunctionalTest):
130
-    sqlalchemy_url = 'sqlite://'
127
+    config_section = 'functional_test_no_db'
131
 
128
 
132
     def init_database(self, settings):
129
     def init_database(self, settings):
133
         self.engine = get_engine(settings)
130
         self.engine = get_engine(settings)

+ 84 - 1
backend/tracim_backend/tests/functional/test_workspaces.py View File

2
 """
2
 """
3
 Tests for /api/v2/workspaces subpath endpoints.
3
 Tests for /api/v2/workspaces subpath endpoints.
4
 """
4
 """
5
-
5
+import requests
6
 import transaction
6
 import transaction
7
 from depot.io.utils import FileIntent
7
 from depot.io.utils import FileIntent
8
 
8
 
600
         assert user_role['workspace_id'] == 1
600
         assert user_role['workspace_id'] == 1
601
 
601
 
602
 
602
 
603
+class TestUserInvitationWithMailActivatedSync(FunctionalTest):
604
+
605
+    fixtures = [BaseFixture, ContentFixtures]
606
+    config_section = 'functional_test_with_mail_test_sync'
607
+
608
+    def test_api__create_workspace_member_role__ok_200__new_user(self):  # nopep8
609
+        """
610
+        Create workspace member role
611
+        :return:
612
+        """
613
+        requests.delete('http://127.0.0.1:8025/api/v1/messages')
614
+        self.testapp.authorization = (
615
+            'Basic',
616
+            (
617
+                'admin@admin.admin',
618
+                'admin@admin.admin'
619
+            )
620
+        )
621
+        # create workspace role
622
+        params = {
623
+            'user_id': None,
624
+            'user_email_or_public_name': 'bob@bob.bob',
625
+            'role': 'content-manager',
626
+        }
627
+        res = self.testapp.post_json(
628
+            '/api/v2/workspaces/1/members',
629
+            status=200,
630
+            params=params,
631
+        )
632
+        user_role_found = res.json_body
633
+        assert user_role_found['role'] == 'content-manager'
634
+        assert user_role_found['user_id']
635
+        user_id = user_role_found['user_id']
636
+        assert user_role_found['workspace_id'] == 1
637
+        assert user_role_found['newly_created'] is True
638
+        assert user_role_found['email_sent'] is True
639
+
640
+        # check mail received
641
+        response = requests.get('http://127.0.0.1:8025/api/v1/messages')
642
+        response = response.json()
643
+        assert len(response) == 1
644
+        headers = response[0]['Content']['Headers']
645
+        assert headers['From'][0] == 'Tracim Notifications <test_user_from+0@localhost>'  # nopep8
646
+        assert headers['To'][0] == 'bob <bob@bob.bob>'
647
+        assert headers['Subject'][0] == '[TRACIM] Created account'
648
+
649
+        # TODO - G.M - 2018-08-02 - Place cleanup outside of the test
650
+        requests.delete('http://127.0.0.1:8025/api/v1/messages')
651
+
652
+
653
+class TestUserInvitationWithMailActivatedASync(FunctionalTest):
654
+
655
+    fixtures = [BaseFixture, ContentFixtures]
656
+    config_section = 'functional_test_with_mail_test_async'
657
+
658
+    def test_api__create_workspace_member_role__ok_200__new_user(self):  # nopep8
659
+        """
660
+        Create workspace member role
661
+        :return:
662
+        """
663
+        self.testapp.authorization = (
664
+            'Basic',
665
+            (
666
+                'admin@admin.admin',
667
+                'admin@admin.admin'
668
+            )
669
+        )
670
+        # create workspace role
671
+        params = {
672
+            'user_id': None,
673
+            'user_email_or_public_name': 'bob@bob.bob',
674
+            'role': 'content-manager',
675
+        }
676
+        res = self.testapp.post_json(
677
+            '/api/v2/workspaces/1/members',
678
+            status=200,
679
+            params=params,
680
+        )
681
+        user_role_found = res.json_body
682
+        assert user_role_found['newly_created'] is True
683
+        assert user_role_found['email_sent'] is False
684
+
685
+
603
 class TestWorkspaceContents(FunctionalTest):
686
 class TestWorkspaceContents(FunctionalTest):
604
     """
687
     """
605
     Tests for /api/v2/workspaces/{workspace_id}/contents endpoint
688
     Tests for /api/v2/workspaces/{workspace_id}/contents endpoint

+ 14 - 0
backend/tracim_backend/tests/library/tests_utils.py View File

1
+import string
2
+
3
+from tracim_backend.lib.utils.utils import password_generator
4
+from tracim_backend.lib.utils.utils import ALLOWED_AUTOGEN_PASSWORD_CHAR
5
+from tracim_backend.lib.utils.utils import DEFAULT_PASSWORD_GEN_CHAR_LENGTH
6
+
7
+
8
+class TestPasswordGenerator(object):
9
+
10
+    def test_password_generator_ok_nominal_case(self):
11
+        password = password_generator()
12
+        assert len(password) == DEFAULT_PASSWORD_GEN_CHAR_LENGTH
13
+        for char in password:
14
+            assert char in ALLOWED_AUTOGEN_PASSWORD_CHAR

+ 9 - 2
backend/tracim_backend/views/core_api/workspace_controller.py View File

31
 from tracim_backend.exceptions import WorkspacesDoNotMatch
31
 from tracim_backend.exceptions import WorkspacesDoNotMatch
32
 from tracim_backend.exceptions import ParentNotFound
32
 from tracim_backend.exceptions import ParentNotFound
33
 from tracim_backend.views.controllers import Controller
33
 from tracim_backend.views.controllers import Controller
34
+from tracim_backend.lib.utils.utils import password_generator
34
 from tracim_backend.views.core_api.schemas import FilterContentQuerySchema
35
 from tracim_backend.views.core_api.schemas import FilterContentQuerySchema
35
 from tracim_backend.views.core_api.schemas import WorkspaceMemberCreationSchema
36
 from tracim_backend.views.core_api.schemas import WorkspaceMemberCreationSchema
36
 from tracim_backend.views.core_api.schemas import WorkspaceMemberInviteSchema
37
 from tracim_backend.views.core_api.schemas import WorkspaceMemberInviteSchema
213
                 # TODO - G.M - 2018-07-05 - [UserCreation] Reenable email
214
                 # TODO - G.M - 2018-07-05 - [UserCreation] Reenable email
214
                 # notification for creation
215
                 # notification for creation
215
                 user = uapi.create_user(
216
                 user = uapi.create_user(
216
-                    hapic_data.body.user_email_or_public_name,
217
-                    do_notify=False
217
+                    email=hapic_data.body.user_email_or_public_name,
218
+                    password= password_generator(),
219
+                    do_notify=True
218
                 )  # nopep8
220
                 )  # nopep8
219
                 newly_created = True
221
                 newly_created = True
222
+                if app_config.EMAIL_NOTIFICATION_ACTIVATED and \
223
+                        app_config.EMAIL_NOTIFICATION_PROCESSING_MODE.lower() == 'sync':
224
+                    email_sent = True
225
+
220
             except EmailValidationFailed:
226
             except EmailValidationFailed:
221
                 raise UserCreationFailed('no valid mail given')
227
                 raise UserCreationFailed('no valid mail given')
228
+
222
         role = rapi.create_one(
229
         role = rapi.create_one(
223
             user=user,
230
             user=user,
224
             workspace=request.current_workspace,
231
             workspace=request.current_workspace,