Browse Source

merge with Feature/578

Guénaël Muller 6 years ago
parent
commit
7435df0618

+ 0 - 267
development.ini.old View File

1
-###
2
-# app configuration
3
-# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
4
-###
5
-[pipeline:main]
6
-pipeline = tracim_web
7
-[app:tracim_web]
8
-use = egg:tracim_backend
9
-
10
-pyramid.reload_templates = true
11
-pyramid.debug_authorization = false
12
-pyramid.debug_notfound = false
13
-pyramid.debug_routematch = false
14
-pyramid.default_locale_name = en
15
-pyramid.includes =
16
-    pyramid_debugtoolbar
17
-
18
-[pipeline:webdav]
19
-pipeline = tracim_webdav
20
-[app:tracim_webdav]
21
-use = egg:tracim_backend#webdav
22
-
23
-[DEFAULT]
24
-sqlalchemy.url = sqlite:///%(here)s/tracim.sqlite
25
-
26
-retry.attempts = 3
27
-
28
-# By default, the toolbar only appears for clients from IP addresses
29
-# '127.0.0.1' and '::1'.
30
-# debugtoolbar.hosts = 127.0.0.1 ::1
31
-
32
-###
33
-# TRACIM SPECIFIC CONF
34
-###
35
-
36
-### Global
37
-
38
-cache_dir = %(here)s/data
39
-# preview generator cache directory
40
-preview_cache_dir = /tmp/tracim/preview/
41
-# file depot storage
42
-depot_storage_name = tracim
43
-depot_storage_dir = %(here)s/depot/
44
-
45
-# The following parameters allow to personalize the home page
46
-# They are html ready (you can put html tags they will be interpreted)
47
-website.title = TRACIM
48
-website.title.color = #555
49
-website.home.subtitle = Default login: email: admin@admin.admin (password: admin@admin.admin)
50
-website.home.tag_line = <div class="text-center" style="font-weight: bold;">Collaboration, versionning and traceability</div>
51
-website.home.below_login_form = in case of problem, please contact the administrator.
52
-# Values may be 'all' or 'folders'
53
-website.treeview.content = all
54
-# The following base_url is used for links and icons
55
-# integrated in the email notifcations
56
-website.base_url = http://127.0.0.1:8080
57
-# If config not provided, it will be extracted from website.base_url
58
-website.server_name = 127.0.0.1
59
-
60
-# Specifies if the update of comments and attached files is allowed (by the owner only).
61
-# Examples:
62
-#    600 means 10 minutes (ie 600 seconds)
63
-#   3600 means 1 hour (60x60 seconds)
64
-#
65
-# Allowed values:
66
-#  -1 means that content update is allowed for ever
67
-#   0 means that content update is not allowed
68
-#   x means that content update is allowed for x seconds (with x>0)
69
-content.update.allowed.duration = 3600
70
-
71
-# Auth type (internal or ldap)
72
-auth_type = internal
73
-# If auth_type is ldap, uncomment following ldap_* parameters
74
-# LDAP server address
75
-# ldap_url = ldap://localhost:389
76
-# Base dn to make queries
77
-# ldap_base_dn = dc=directory,dc=fsf,dc=org
78
-# Bind dn to identify the search
79
-# ldap_bind_dn = cn=admin,dc=directory,dc=fsf,dc=org
80
-# The bind password
81
-# ldap_bind_pass = toor
82
-# Attribute name of user record who contain user login (email)
83
-# ldap_ldap_naming_attribute = uid
84
-# Matching between ldap attribute and ldap user field (ldap_attr1=user_field1,ldap_attr2=user_field2,...)
85
-# ldap_user_attributes = mail=email
86
-# TLS usage to communicate with your LDAP server
87
-# ldap_tls = False
88
-# If True, LDAP own tracim group managment (not available for now!)
89
-# ldap_group_enabled = False
90
-# User auth token validity in seconds (used to interfaces like web calendars)
91
-user.auth_token.validity = 604800
92
-
93
-### Mail
94
-
95
-# Reset password through email related configuration.
96
-# These emails will be sent through SMTP
97
-#
98
-resetpassword.email_sender = email@sender.com
99
-resetpassword.smtp_host = smtp.sender
100
-resetpassword.smtp_port = 25
101
-resetpassword.smtp_login = smtp.login
102
-resetpassword.smtp_passwd = smtp.password
103
-
104
-email.notification.activated = False
105
-# email.notification.log_file_path = /tmp/mail-notifications.log
106
-# email notifications can be sent with the user_id added as an identifier
107
-# this way email clients like Thunderbird will be able to distinguish
108
-# notifications generated by a user or another one
109
-email.notification.from.email = noreply+{user_id}@trac.im
110
-email.notification.from.default_label = Tracim Notifications
111
-email.notification.reply_to.email = reply+{content_id}@trac.im
112
-email.notification.references.email = thread+{content_id}@trac.im
113
-email.notification.content_update.template.html = %(here)s/tracim/templates/mail/content_update_body_html.mak
114
-email.notification.content_update.template.text = %(here)s/tracim/templates/mail/content_update_body_text.mak
115
-email.notification.created_account.template.html = %(here)s/tracim/templates/mail/created_account_body_html.mak
116
-email.notification.created_account.template.text = %(here)s/tracim/templates/mail/created_account_body_text.mak
117
-# Note: items between { and } are variable names. Do not remove / rename them
118
-email.notification.content_update.subject = [{website_title}] [{workspace_label}] {content_label} ({content_status_label})
119
-email.notification.created_account.subject = [{website_title}] Created account
120
-# processing_mode may be sync or async
121
-email.notification.processing_mode = sync
122
-email.notification.smtp.server = your_smtp_server
123
-email.notification.smtp.port = 25
124
-email.notification.smtp.user = your_smtp_user
125
-email.notification.smtp.password = your_smtp_password
126
-
127
-## Email sending configuration
128
-# processing_mode may be sync or async,
129
-# with async, please configure redis below
130
-email.processing_mode = sync
131
-# email.async.redis.host = localhost
132
-# email.async.redis.port = 6379
133
-# email.async.redis.db = 0
134
-
135
-# Email reply configuration
136
-email.reply.activated = False
137
-email.reply.imap.server = your_imap_server
138
-email.reply.imap.port = 993
139
-email.reply.imap.user = your_imap_user
140
-email.reply.imap.password = your_imap_password
141
-email.reply.imap.folder = INBOX
142
-email.reply.imap.use_ssl = true
143
-email.reply.imap.use_idle = true
144
-# Re-new connection each 10 minutes
145
-email.reply.connection.max_lifetime = 600
146
-# Token for communication between mail fetcher and tracim controller
147
-email.reply.token = mysecuretoken
148
-# Delay in seconds between each check
149
-email.reply.check.heartbeat = 60
150
-email.reply.use_html_parsing = true
151
-email.reply.use_txt_parsing = true
152
-# Lockfile path is required for email_reply feature,
153
-# it's just an empty file use to prevent concurrent access to imap unseen mail
154
-email.reply.lockfile_path = %(here)s/email_fetcher.lock
155
-
156
-### Radical (CalDav server) configuration
157
-
158
-# radicale.server.host = 0.0.0.0
159
-# radicale.server.port = 5232
160
-# radicale.server.ssl = false
161
-radicale.server.filesystem.folder = %(here)s/radicale/collections/
162
-# radicale.server.allow_origin = *
163
-# radicale.server.realm_message = Tracim Calendar - Password Required
164
-## url can be extended like http://127.0.0.1:5232/calendar
165
-## in this case, you have to create your own proxy behind this url.
166
-## and update following parameters
167
-# radicale.client.base_url.host = http://127.0.0.1:5232
168
-# radicale.client.base_url.prefix = /
169
-
170
-### WSGIDAV
171
-
172
-wsgidav.config_path = %(here)s/wsgidav.conf
173
-## url can be extended like 127.0.0.1/webdav
174
-## in this case, you have to create your own proxy behind this url.
175
-## Do not set http:// prefix.
176
-# wsgidav.client.base_url = 127.0.0.1:<WSGIDAV_PORT>
177
-
178
-###
179
-# wsgi server configuration
180
-###
181
-
182
-[server:main]
183
-use = egg:waitress#main
184
-listen = localhost:6543
185
-
186
-[alembic]
187
-# path to migration scripts
188
-script_location = tracim/migration
189
-
190
-# template used to generate migration files
191
-# file_template = %%(rev)s_%%(slug)s
192
-
193
-# timezone to use when rendering the date
194
-# within the migration file as well as the filename.
195
-# string value is passed to dateutil.tz.gettz()
196
-# leave blank for localtime
197
-# timezone =
198
-
199
-# max length of characters to apply to the
200
-# "slug" field
201
-#truncate_slug_length = 40
202
-
203
-# set to 'true' to run the environment during
204
-# the 'revision' command, regardless of autogenerate
205
-# revision_environment = false
206
-
207
-# set to 'true' to allow .pyc and .pyo files without
208
-# a source .py file to be detected as revisions in the
209
-# versions/ directory
210
-# sourceless = false
211
-
212
-# version location specification; this defaults
213
-# to migrate/versions.  When using multiple version
214
-# directories, initial revisions must be specified with --version-path
215
-# version_locations = %(here)s/bar %(here)s/bat migrate/versions
216
-
217
-# the output encoding used when revision files
218
-# are written from script.py.mako
219
-# output_encoding = utf-8
220
-
221
-sqlalchemy.url = sqlite:///%(here)s/tracim.sqlite
222
-
223
-###
224
-# logging configuration
225
-# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
226
-###
227
-
228
-[loggers]
229
-keys = root, tracim, sqlalchemy, alembic
230
-
231
-[handlers]
232
-keys = console
233
-
234
-[formatters]
235
-keys = generic
236
-
237
-[logger_root]
238
-level = INFO
239
-handlers = console
240
-
241
-[logger_tracim]
242
-level = DEBUG
243
-handlers =
244
-qualname = tracim
245
-
246
-[logger_sqlalchemy]
247
-level = INFO
248
-handlers =
249
-qualname = sqlalchemy.engine
250
-# "level = INFO" logs SQL queries.
251
-# "level = DEBUG" logs SQL queries and results.
252
-# "level = WARN" logs neither.  (Recommended for production systems.)
253
-
254
-[logger_alembic]
255
-level = INFO
256
-handlers =
257
-qualname = alembic
258
-
259
-[handler_console]
260
-class = StreamHandler
261
-args = (sys.stderr,)
262
-level = NOTSET
263
-formatter = generic
264
-
265
-[formatter_generic]
266
-format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
267
-datefmt = %H:%M:%S

+ 4 - 1
tracim/exceptions.py View File

93
     pass
93
     pass
94
 
94
 
95
 
95
 
96
-class UserNotExist(TracimException):
96
+class UserDoesNotExist(TracimException):
97
+    pass
98
+
99
+class UserNotFoundInTracimRequest(TracimException):
97
     pass
100
     pass

+ 0 - 1
tracim/lib/core/group.py View File

17
             session: Session,
17
             session: Session,
18
             current_user: typing.Optional[User],
18
             current_user: typing.Optional[User],
19
             config: CFG
19
             config: CFG
20
-
21
     ):
20
     ):
22
         self._user = current_user
21
         self._user = current_user
23
         self._session = session
22
         self._session = session

+ 11 - 10
tracim/lib/core/user.py View File

7
 from sqlalchemy.orm import Session
7
 from sqlalchemy.orm import Session
8
 
8
 
9
 from tracim import CFG
9
 from tracim import CFG
10
-from tracim.models.auth import User, Group
10
+from tracim.models.auth import User
11
+from tracim.models.auth import Group
11
 from sqlalchemy.orm.exc import NoResultFound
12
 from sqlalchemy.orm.exc import NoResultFound
12
-from tracim.exceptions import WrongUserPassword, UserNotExist
13
+from tracim.exceptions import WrongUserPassword, UserDoesNotExist
13
 from tracim.exceptions import AuthenticationFailed
14
 from tracim.exceptions import AuthenticationFailed
14
 from tracim.models.context_models import UserInContext
15
 from tracim.models.context_models import UserInContext
15
 
16
 
48
         """
49
         """
49
         try:
50
         try:
50
             user = self._base_query().filter(User.user_id == user_id).one()
51
             user = self._base_query().filter(User.user_id == user_id).one()
51
-        except NoResultFound:
52
-            raise UserNotExist()
52
+        except NoResultFound as exc:
53
+            raise UserDoesNotExist('User "{}" not found in database'.format(user_id)) from exc  # nopep8
53
         return user
54
         return user
54
 
55
 
55
     def get_one_by_email(self, email: str) -> User:
56
     def get_one_by_email(self, email: str) -> User:
60
         """
61
         """
61
         try:
62
         try:
62
             user = self._base_query().filter(User.email == email).one()
63
             user = self._base_query().filter(User.email == email).one()
63
-        except NoResultFound:
64
-            raise UserNotExist()
64
+        except NoResultFound as exc:
65
+            raise UserDoesNotExist('User "{}" not found in database'.format(email)) from exc  # nopep8
65
         return user
66
         return user
66
 
67
 
67
     # FIXME - G.M - 24-04-2018 - Duplicate method with get_one.
68
     # FIXME - G.M - 24-04-2018 - Duplicate method with get_one.
73
         Get current_user
74
         Get current_user
74
         """
75
         """
75
         if not self._user:
76
         if not self._user:
76
-            raise UserNotExist()
77
+            raise UserDoesNotExist('There is no current user')
77
         return self._user
78
         return self._user
78
 
79
 
79
     def get_all(self) -> typing.Iterable[User]:
80
     def get_all(self) -> typing.Iterable[User]:
102
             if user.validate_password(password):
103
             if user.validate_password(password):
103
                 return user
104
                 return user
104
             else:
105
             else:
105
-                raise WrongUserPassword()
106
-        except (WrongUserPassword, NoResultFound, UserNotExist):
107
-            raise AuthenticationFailed()
106
+                raise WrongUserPassword('User "{}" password is incorrect'.format(email))  # nopep8
107
+        except (WrongUserPassword, UserDoesNotExist) as exc:
108
+            raise AuthenticationFailed('User "{}" authentication failed'.format(email)) from exc  # nopep8
108
 
109
 
109
     # Actions
110
     # Actions
110
 
111
 

+ 29 - 22
tracim/lib/core/userworkspace.py View File

7
 __author__ = 'damien'
7
 __author__ = 'damien'
8
 
8
 
9
 from sqlalchemy.orm import Session
9
 from sqlalchemy.orm import Session
10
-from tracim.models.auth import User, Group
10
+from sqlalchemy.orm import Query
11
+from tracim.models.auth import User
11
 from tracim.models.data import Workspace
12
 from tracim.models.data import Workspace
12
 from tracim.models.data import UserRoleInWorkspace
13
 from tracim.models.data import UserRoleInWorkspace
13
 from tracim.models.data import RoleType
14
 from tracim.models.data import RoleType
73
 
74
 
74
         return role
75
         return role
75
 
76
 
76
-    def __init__(self,
77
-                 session: Session,
78
-                 current_user: typing.Optional[User],
79
-                 config: CFG):
77
+    def __init__(
78
+        self,
79
+        session: Session,
80
+        current_user: typing.Optional[User],
81
+        config: CFG,
82
+    )-> None:
80
         self._session = session
83
         self._session = session
81
         self._user = current_user
84
         self._user = current_user
82
         self._config = config
85
         self._config = config
83
 
86
 
84
-    def _get_one_rsc(self, user_id, workspace_id):
87
+    def _get_one_rsc(self, user_id: int, workspace_id: int) -> Query:
85
         """
88
         """
86
         :param user_id:
89
         :param user_id:
87
         :param workspace_id:
90
         :param workspace_id:
91
             filter(UserRoleInWorkspace.workspace_id == workspace_id).\
94
             filter(UserRoleInWorkspace.workspace_id == workspace_id).\
92
             filter(UserRoleInWorkspace.user_id == user_id)
95
             filter(UserRoleInWorkspace.user_id == user_id)
93
 
96
 
94
-    def get_one(self, user_id, workspace_id):
97
+    def get_one(self, user_id: int, workspace_id: int) -> UserRoleInWorkspace:
95
         return self._get_one_rsc(user_id, workspace_id).one()
98
         return self._get_one_rsc(user_id, workspace_id).one()
96
 
99
 
97
     def create_one(
100
     def create_one(
98
-            self,
99
-            user: User,
100
-            workspace: Workspace,
101
-            role_level: int,
102
-            with_notif: bool,
103
-            flush: bool=True
101
+        self,
102
+        user: User,
103
+        workspace: Workspace,
104
+        role_level: int,
105
+        with_notif: bool,
106
+        flush: bool=True
104
     ) -> UserRoleInWorkspace:
107
     ) -> UserRoleInWorkspace:
105
         role = self.create_role()
108
         role = self.create_role()
106
         role.user_id = user.user_id
109
         role.user_id = user.user_id
111
             self._session.flush()
114
             self._session.flush()
112
         return role
115
         return role
113
 
116
 
114
-    def delete_one(self, user_id, workspace_id, flush=True):
117
+    def delete_one(self, user_id: int, workspace_id: int, flush=True) -> None:
115
         self._get_one_rsc(user_id, workspace_id).delete()
118
         self._get_one_rsc(user_id, workspace_id).delete()
116
         if flush:
119
         if flush:
117
             self._session.flush()
120
             self._session.flush()
118
 
121
 
119
-    def _get_all_for_user(self, user_id):
122
+    def _get_all_for_user(self, user_id) -> typing.List[UserRoleInWorkspace]:
120
         return self._session.query(UserRoleInWorkspace)\
123
         return self._session.query(UserRoleInWorkspace)\
121
             .filter(UserRoleInWorkspace.user_id == user_id)
124
             .filter(UserRoleInWorkspace.user_id == user_id)
122
 
125
 
123
-    def get_all_for_user(self, user: User):
126
+    def get_all_for_user(self, user: User) -> typing.List[UserRoleInWorkspace]:
124
         return self._get_all_for_user(user.user_id).all()
127
         return self._get_all_for_user(user.user_id).all()
125
 
128
 
126
     def get_all_for_user_order_by_workspace(
129
     def get_all_for_user_order_by_workspace(
127
-            self,
128
-            user_id: int
129
-    ) -> UserRoleInWorkspace:
130
+        self,
131
+        user_id: int
132
+    ) -> typing.List[UserRoleInWorkspace]:
130
         return self._get_all_for_user(user_id)\
133
         return self._get_all_for_user(user_id)\
131
             .join(UserRoleInWorkspace.workspace).order_by(Workspace.label).all()
134
             .join(UserRoleInWorkspace.workspace).order_by(Workspace.label).all()
132
 
135
 
133
-    def get_all_for_workspace(self, workspace:Workspace):
136
+    def get_all_for_workspace(
137
+        self,
138
+        workspace:Workspace
139
+    ) -> typing.List[UserRoleInWorkspace]:
134
         return self._session.query(UserRoleInWorkspace)\
140
         return self._session.query(UserRoleInWorkspace)\
135
             .filter(UserRoleInWorkspace.workspace_id == workspace.workspace_id).all()  # nopep8
141
             .filter(UserRoleInWorkspace.workspace_id == workspace.workspace_id).all()  # nopep8
136
 
142
 
137
-    def save(self, role: UserRoleInWorkspace):
143
+    def save(self, role: UserRoleInWorkspace) -> None:
138
         self._session.flush()
144
         self._session.flush()
139
 
145
 
146
+    # TODO - G.M - 07-06-2018 - [Cleanup] Check if this method is already needed
140
     @classmethod
147
     @classmethod
141
-    def get_roles_for_select_field(cls):
148
+    def get_roles_for_select_field(cls) -> typing.List[RoleType]:
142
         """
149
         """
143
 
150
 
144
         :return: list of DictLikeClass instances representing available Roles
151
         :return: list of DictLikeClass instances representing available Roles

+ 2 - 2
tracim/lib/utils/authentification.py View File

4
 from sqlalchemy.orm.exc import NoResultFound
4
 from sqlalchemy.orm.exc import NoResultFound
5
 
5
 
6
 from tracim import TracimRequest
6
 from tracim import TracimRequest
7
-from tracim.exceptions import UserNotExist
7
+from tracim.exceptions import UserDoesNotExist
8
 from tracim.lib.core.user import UserApi
8
 from tracim.lib.core.user import UserApi
9
 from tracim.models import User
9
 from tracim.models import User
10
 
10
 
51
         if not login:
51
         if not login:
52
             return None
52
             return None
53
         user = uapi.get_one_by_email(login)
53
         user = uapi.get_one_by_email(login)
54
-    except (NoResultFound, UserNotExist):
54
+    except (NoResultFound, UserDoesNotExist):
55
         return None
55
         return None
56
     return user
56
     return user

+ 1 - 1
tracim/lib/utils/authorization.py View File

100
             raise InsufficientUserWorkspaceRole()
100
             raise InsufficientUserWorkspaceRole()
101
 
101
 
102
         return wrapper
102
         return wrapper
103
-    return decorator
103
+    return decorator

+ 10 - 8
tracim/lib/utils/request.py View File

5
 from pyramid.request import Request
5
 from pyramid.request import Request
6
 from sqlalchemy.orm.exc import NoResultFound
6
 from sqlalchemy.orm.exc import NoResultFound
7
 
7
 
8
-from tracim.exceptions import NotAuthentificated, UserNotExist
8
+
9
+from tracim.exceptions import NotAuthentificated
10
+from tracim.exceptions import UserNotFoundInTracimRequest
11
+from tracim.exceptions import UserDoesNotExist
9
 from tracim.exceptions import WorkspaceNotFound
12
 from tracim.exceptions import WorkspaceNotFound
10
 from tracim.exceptions import ImmutableAttribute
13
 from tracim.exceptions import ImmutableAttribute
11
 from tracim.lib.core.user import UserApi
14
 from tracim.lib.core.user import UserApi
142
         if 'user_id' in request.matchdict:
145
         if 'user_id' in request.matchdict:
143
             login = request.matchdict['user_id']
146
             login = request.matchdict['user_id']
144
         if not login:
147
         if not login:
145
-            raise UserNotExist('no user_id found, incorrect request ?')
148
+            raise UserNotFoundInTracimRequest('You request a candidate user but the context not permit to found one')  # nopep8
146
         user = uapi.get_one(login)
149
         user = uapi.get_one(login)
147
-    except NoResultFound:
148
-        raise NotAuthentificated('User not found')
150
+    except UserNotFoundInTracimRequest as exc:
151
+        raise UserDoesNotExist('User {} not found'.format(login)) from exc
149
     return user
152
     return user
150
 
153
 
151
 
154
 
162
     try:
165
     try:
163
         login = request.authenticated_userid
166
         login = request.authenticated_userid
164
         if not login:
167
         if not login:
165
-            raise NotAuthentificated('not authenticated user_id,'
166
-                                     'Failed Authentification ?')
168
+            raise UserNotFoundInTracimRequest('You request a current user but the context not permit to found one')  # nopep8
167
         user = uapi.get_one_by_email(login)
169
         user = uapi.get_one_by_email(login)
168
-    except NoResultFound:
169
-        raise NotAuthentificated('User not found')
170
+    except (UserDoesNotExist, UserNotFoundInTracimRequest) as exc:
171
+        raise NotAuthentificated('User {} not found'.format(login)) from exc
170
     return user
172
     return user
171
 
173
 
172
 
174
 

+ 10 - 10
tracim/models/applications.py View File

25
         self.main_route = main_route
25
         self.main_route = main_route
26
 
26
 
27
 
27
 
28
-# TODO - G.M - 21-05-2018 Do not rely on hardcoded app list
29
 # default apps
28
 # default apps
30
 calendar = Application(
29
 calendar = Application(
31
     label='Calendar',
30
     label='Calendar',
58
     main_route='/#/workspaces/{workspace_id}/contents?type=file',
57
     main_route='/#/workspaces/{workspace_id}/contents?type=file',
59
 )
58
 )
60
 
59
 
61
-pagemarkdownplus = Application(
62
-    label='Rich Markdown Files',  # TODO - G.M - 24-05-2018 - Check label
63
-    slug='contents/pagemarkdownplus',
60
+markdownpluspage = Application(
61
+    label='Markdown Plus Documents',  # TODO - G.M - 24-05-2018 - Check label
62
+    slug='contents/markdownpluspage',
64
     icon='file-code',
63
     icon='file-code',
65
     hexcolor='#f12d2d',
64
     hexcolor='#f12d2d',
66
     is_active=True,
65
     is_active=True,
67
     config={},
66
     config={},
68
-    main_route='/#/workspaces/{workspace_id}/contents?type=pagemarkdownplus',
67
+    main_route='/#/workspaces/{workspace_id}/contents?type=markdownpluspage',
69
 )
68
 )
70
 
69
 
71
-pagehtml = Application(
70
+htmlpage = Application(
72
     label='Text Documents',  # TODO - G.M - 24-05-2018 - Check label
71
     label='Text Documents',  # TODO - G.M - 24-05-2018 - Check label
73
-    slug='contents/pagehtml',
72
+    slug='contents/htmlpage',
74
     icon='file-text-o',
73
     icon='file-text-o',
75
     hexcolor='#3f52e3',
74
     hexcolor='#3f52e3',
76
     is_active=True,
75
     is_active=True,
77
     config={},
76
     config={},
78
-    main_route='/#/workspaces/{workspace_id}/contents?type=pagehtml',
77
+    main_route='/#/workspaces/{workspace_id}/contents?type=htmlpage',
79
 )
78
 )
79
+# TODO - G.M - 08-06-2018 - This is hardcoded lists of app, make this dynamic.
80
 # List of applications
80
 # List of applications
81
 applications = [
81
 applications = [
82
-    pagehtml,
83
-    pagemarkdownplus,
82
+    htmlpage,
83
+    markdownpluspage,
84
     file,
84
     file,
85
     thread,
85
     thread,
86
     calendar,
86
     calendar,

+ 13 - 9
tracim/models/auth.py View File

91
 class Profile(object):
91
 class Profile(object):
92
     """This model is the "max" group associated to a given user."""
92
     """This model is the "max" group associated to a given user."""
93
 
93
 
94
-    _NAME = [Group.TIM_NOBODY_GROUPNAME,
95
-             Group.TIM_USER_GROUPNAME,
96
-             Group.TIM_MANAGER_GROUPNAME,
97
-             Group.TIM_ADMIN_GROUPNAME]
98
-
99
-    _IDS = [Group.TIM_NOBODY,
100
-            Group.TIM_USER,
101
-            Group.TIM_MANAGER,
102
-            Group.TIM_ADMIN]
94
+    _NAME = [
95
+        Group.TIM_NOBODY_GROUPNAME,
96
+        Group.TIM_USER_GROUPNAME,
97
+        Group.TIM_MANAGER_GROUPNAME,
98
+        Group.TIM_ADMIN_GROUPNAME,
99
+    ]
100
+
101
+    _IDS = [
102
+        Group.TIM_NOBODY,
103
+        Group.TIM_USER,
104
+        Group.TIM_MANAGER,
105
+        Group.TIM_ADMIN,
106
+    ]
103
 
107
 
104
     # TODO - G.M - 18-04-2018 [Cleanup] Drop this
108
     # TODO - G.M - 18-04-2018 [Cleanup] Drop this
105
     # _LABEL = [l_('Nobody'),
109
     # _LABEL = [l_('Nobody'),

+ 2 - 2
tracim/models/context_models.py View File

8
 from tracim.models import User
8
 from tracim.models import User
9
 from tracim.models.auth import Profile
9
 from tracim.models.auth import Profile
10
 from tracim.models.data import Workspace, UserRoleInWorkspace
10
 from tracim.models.data import Workspace, UserRoleInWorkspace
11
-from tracim.models.workspace_menu_entries import default_workspace_menu_entry, \
12
-    WorkspaceMenuEntry
11
+from tracim.models.workspace_menu_entries import default_workspace_menu_entry
12
+from tracim.models.workspace_menu_entries import WorkspaceMenuEntry
13
 
13
 
14
 
14
 
15
 class LoginCredentials(object):
15
 class LoginCredentials(object):

+ 7 - 6
tracim/models/data.py View File

131
     WORKSPACE_MANAGER = 8
131
     WORKSPACE_MANAGER = 8
132
 
132
 
133
     # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
133
     # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
134
-    SLUG = dict()
135
-    SLUG[NOT_APPLICABLE] = 'not_applicable'
136
-    SLUG[READER] = 'reader'
137
-    SLUG[CONTRIBUTOR] = 'contributor'
138
-    SLUG[CONTENT_MANAGER] = 'content_manager'
139
-    SLUG[WORKSPACE_MANAGER] = 'workspace_manager'
134
+    SLUG = {
135
+        NOT_APPLICABLE: 'not_applicable',
136
+        READER: 'reader',
137
+        CONTRIBUTOR: 'contributor',
138
+        CONTENT_MANAGER: 'content_manager',
139
+        WORKSPACE_MANAGER: 'workspace_manager',
140
+    }
140
 
141
 
141
     # LABEL = dict()
142
     # LABEL = dict()
142
     # LABEL[0] = l_('N/A')
143
     # LABEL[0] = l_('N/A')

+ 2 - 2
tracim/models/workspace_menu_entries.py View File

24
         self.hexcolor = hexcolor
24
         self.hexcolor = hexcolor
25
         self.icon = icon
25
         self.icon = icon
26
 
26
 
27
-
28
 dashboard_menu_entry = WorkspaceMenuEntry(
27
 dashboard_menu_entry = WorkspaceMenuEntry(
29
   slug='dashboard',
28
   slug='dashboard',
30
   label='Dashboard',
29
   label='Dashboard',
40
   icon="",
39
   icon="",
41
 )
40
 )
42
 
41
 
43
-
42
+# TODO - G.M - 08-06-2018 - This is hardcoded default menu entry,
43
+#  of app, make this dynamic (and loaded from application system)
44
 def default_workspace_menu_entry(
44
 def default_workspace_menu_entry(
45
     workspace: Workspace,
45
     workspace: Workspace,
46
 )-> typing.List[WorkspaceMenuEntry]:
46
 )-> typing.List[WorkspaceMenuEntry]:

+ 3 - 3
tracim/tests/functional/test_system.py View File

25
         res = res.json_body
25
         res = res.json_body
26
         application = res[0]
26
         application = res[0]
27
         assert application['label'] == "Text Documents"
27
         assert application['label'] == "Text Documents"
28
-        assert application['slug'] == 'contents/pagehtml'
28
+        assert application['slug'] == 'contents/htmlpage'
29
         assert application['icon'] == 'file-text-o'
29
         assert application['icon'] == 'file-text-o'
30
         assert application['hexcolor'] == '#3f52e3'
30
         assert application['hexcolor'] == '#3f52e3'
31
         assert application['is_active'] is True
31
         assert application['is_active'] is True
32
         assert 'config' in application
32
         assert 'config' in application
33
         application = res[1]
33
         application = res[1]
34
-        assert application['label'] == "Rich Markdown Files"
35
-        assert application['slug'] == 'contents/pagemarkdownplus'
34
+        assert application['label'] == "Markdown Plus Documents"
35
+        assert application['slug'] == 'contents/markdownpluspage'
36
         assert application['icon'] == 'file-code'
36
         assert application['icon'] == 'file-code'
37
         assert application['hexcolor'] == '#f12d2d'
37
         assert application['hexcolor'] == '#f12d2d'
38
         assert application['is_active'] is True
38
         assert application['is_active'] is True

+ 5 - 5
tracim/tests/functional/test_user.py View File

47
         assert sidebar_entry['icon'] == ""
47
         assert sidebar_entry['icon'] == ""
48
 
48
 
49
         sidebar_entry = workspace['sidebar_entries'][2]
49
         sidebar_entry = workspace['sidebar_entries'][2]
50
-        assert sidebar_entry['slug'] == 'contents/pagehtml'
50
+        assert sidebar_entry['slug'] == 'contents/htmlpage'
51
         assert sidebar_entry['label'] == 'Text Documents'
51
         assert sidebar_entry['label'] == 'Text Documents'
52
-        assert sidebar_entry['route'] == '/#/workspaces/1/contents?type=pagehtml'  # nopep8
52
+        assert sidebar_entry['route'] == '/#/workspaces/1/contents?type=htmlpage'  # nopep8
53
         assert sidebar_entry['hexcolor'] == "#3f52e3"
53
         assert sidebar_entry['hexcolor'] == "#3f52e3"
54
         assert sidebar_entry['icon'] == "file-text-o"
54
         assert sidebar_entry['icon'] == "file-text-o"
55
 
55
 
56
         sidebar_entry = workspace['sidebar_entries'][3]
56
         sidebar_entry = workspace['sidebar_entries'][3]
57
-        assert sidebar_entry['slug'] == 'contents/pagemarkdownplus'
58
-        assert sidebar_entry['label'] == 'Rich Markdown Files'
59
-        assert sidebar_entry['route'] == "/#/workspaces/1/contents?type=pagemarkdownplus"    # nopep8
57
+        assert sidebar_entry['slug'] == 'contents/markdownpluspage'
58
+        assert sidebar_entry['label'] == 'Markdown Plus Documents'
59
+        assert sidebar_entry['route'] == "/#/workspaces/1/contents?type=markdownpluspage"    # nopep8
60
         assert sidebar_entry['hexcolor'] == "#f12d2d"
60
         assert sidebar_entry['hexcolor'] == "#f12d2d"
61
         assert sidebar_entry['icon'] == "file-code"
61
         assert sidebar_entry['icon'] == "file-code"
62
 
62
 

+ 5 - 5
tracim/tests/functional/test_workspaces.py View File

48
         assert sidebar_entry['icon'] == ""
48
         assert sidebar_entry['icon'] == ""
49
 
49
 
50
         sidebar_entry = workspace['sidebar_entries'][2]
50
         sidebar_entry = workspace['sidebar_entries'][2]
51
-        assert sidebar_entry['slug'] == 'contents/pagehtml'
51
+        assert sidebar_entry['slug'] == 'contents/htmlpage'
52
         assert sidebar_entry['label'] == 'Text Documents'
52
         assert sidebar_entry['label'] == 'Text Documents'
53
-        assert sidebar_entry['route'] == '/#/workspaces/1/contents?type=pagehtml'  # nopep8
53
+        assert sidebar_entry['route'] == '/#/workspaces/1/contents?type=htmlpage'  # nopep8
54
         assert sidebar_entry['hexcolor'] == "#3f52e3"
54
         assert sidebar_entry['hexcolor'] == "#3f52e3"
55
         assert sidebar_entry['icon'] == "file-text-o"
55
         assert sidebar_entry['icon'] == "file-text-o"
56
 
56
 
57
         sidebar_entry = workspace['sidebar_entries'][3]
57
         sidebar_entry = workspace['sidebar_entries'][3]
58
-        assert sidebar_entry['slug'] == 'contents/pagemarkdownplus'
59
-        assert sidebar_entry['label'] == 'Rich Markdown Files'
60
-        assert sidebar_entry['route'] == "/#/workspaces/1/contents?type=pagemarkdownplus"    # nopep8
58
+        assert sidebar_entry['slug'] == 'contents/markdownpluspage'
59
+        assert sidebar_entry['label'] == 'Markdown Plus Documents'
60
+        assert sidebar_entry['route'] == "/#/workspaces/1/contents?type=markdownpluspage"    # nopep8
61
         assert sidebar_entry['hexcolor'] == "#f12d2d"
61
         assert sidebar_entry['hexcolor'] == "#f12d2d"
62
         assert sidebar_entry['icon'] == "file-code"
62
         assert sidebar_entry['icon'] == "file-code"
63
 
63
 

+ 3 - 3
tracim/tests/library/test_user_api.py View File

4
 
4
 
5
 import transaction
5
 import transaction
6
 
6
 
7
-from tracim.exceptions import UserNotExist, AuthenticationFailed
7
+from tracim.exceptions import UserDoesNotExist, AuthenticationFailed
8
 from tracim.lib.core.user import UserApi
8
 from tracim.lib.core.user import UserApi
9
 from tracim.models import User
9
 from tracim.models import User
10
 from tracim.models.context_models import UserInContext
10
 from tracim.models.context_models import UserInContext
60
             session=self.session,
60
             session=self.session,
61
             config=self.config,
61
             config=self.config,
62
         )
62
         )
63
-        with pytest.raises(UserNotExist):
63
+        with pytest.raises(UserDoesNotExist):
64
             api.get_one_by_email('unknown')
64
             api.get_one_by_email('unknown')
65
 
65
 
66
     # def test_unit__get_all__ok__nominal_case(self):
66
     # def test_unit__get_all__ok__nominal_case(self):
127
             session=self.session,
127
             session=self.session,
128
             config=self.config,
128
             config=self.config,
129
         )
129
         )
130
-        with pytest.raises(UserNotExist):
130
+        with pytest.raises(UserDoesNotExist):
131
             api.get_current_user()
131
             api.get_current_user()
132
 
132
 
133
     def test_unit__authenticate_user___ok__nominal_case(self):
133
     def test_unit__authenticate_user___ok__nominal_case(self):

+ 6 - 12
tracim/views/core_api/schemas.py View File

127
         description = 'Entry element of a workspace menu'
127
         description = 'Entry element of a workspace menu'
128
 
128
 
129
 
129
 
130
-class WorkspaceSchema(marshmallow.Schema):
130
+class WorkspaceDigestSchema(marshmallow.Schema):
131
     id = marshmallow.fields.Int(example=4)
131
     id = marshmallow.fields.Int(example=4)
132
-    slug = marshmallow.fields.String(example='intranet')
133
     label = marshmallow.fields.String(example='Intranet')
132
     label = marshmallow.fields.String(example='Intranet')
134
-    description = marshmallow.fields.String(example='All intranet data.')
135
     sidebar_entries = marshmallow.fields.Nested(
133
     sidebar_entries = marshmallow.fields.Nested(
136
         WorkspaceMenuEntrySchema,
134
         WorkspaceMenuEntrySchema,
137
         many=True,
135
         many=True,
138
     )
136
     )
139
 
137
 
140
     class Meta:
138
     class Meta:
141
-        description = 'Full workspace informations'
139
+        description = 'Digest of workspace informations'
142
 
140
 
143
 
141
 
144
-class WorkspaceDigestSchema(marshmallow.Schema):
145
-    id = marshmallow.fields.Int(example=4)
146
-    label = marshmallow.fields.String(example='Intranet')
147
-    sidebar_entries = marshmallow.fields.Nested(
148
-        WorkspaceMenuEntrySchema,
149
-        many=True,
150
-    )
142
+class WorkspaceSchema(WorkspaceDigestSchema):
143
+    slug = marshmallow.fields.String(example='intranet')
144
+    description = marshmallow.fields.String(example='All intranet data.')
151
 
145
 
152
     class Meta:
146
     class Meta:
153
-        description = 'Digest of workspace informations'
147
+        description = 'Full workspace informations'
154
 
148
 
155
 
149
 
156
 class WorkspaceMemberSchema(marshmallow.Schema):
150
 class WorkspaceMemberSchema(marshmallow.Schema):

+ 10 - 7
tracim/views/core_api/user_controller.py View File

11
     from http import client as HTTPStatus
11
     from http import client as HTTPStatus
12
 
12
 
13
 from tracim import hapic, TracimRequest
13
 from tracim import hapic, TracimRequest
14
-from tracim.exceptions import NotAuthentificated, InsufficientUserProfile, \
15
-    UserNotExist
16
-from tracim.lib.core.user import UserApi
14
+
15
+from tracim.exceptions import NotAuthentificated
16
+from tracim.exceptions import InsufficientUserProfile
17
+from tracim.exceptions import UserDoesNotExist
17
 from tracim.lib.core.workspace import WorkspaceApi
18
 from tracim.lib.core.workspace import WorkspaceApi
18
 from tracim.views.controllers import Controller
19
 from tracim.views.controllers import Controller
19
-from tracim.views.core_api.schemas import UserIdPathSchema, \
20
-    WorkspaceDigestSchema
20
+from tracim.views.core_api.schemas import UserIdPathSchema
21
+from tracim.views.core_api.schemas import WorkspaceDigestSchema
21
 
22
 
22
 
23
 
23
 class UserController(Controller):
24
 class UserController(Controller):
25
     @hapic.with_api_doc()
26
     @hapic.with_api_doc()
26
     @hapic.handle_exception(NotAuthentificated, HTTPStatus.UNAUTHORIZED)
27
     @hapic.handle_exception(NotAuthentificated, HTTPStatus.UNAUTHORIZED)
27
     @hapic.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
28
     @hapic.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
28
-    @hapic.handle_exception(UserNotExist, HTTPStatus.NOT_FOUND)
29
+    @hapic.handle_exception(UserDoesNotExist, HTTPStatus.NOT_FOUND)
29
     @require_same_user_or_profile(Group.TIM_ADMIN)
30
     @require_same_user_or_profile(Group.TIM_ADMIN)
30
     @hapic.input_path(UserIdPathSchema())
31
     @hapic.input_path(UserIdPathSchema())
31
     @hapic.output_body(WorkspaceDigestSchema(many=True),)
32
     @hapic.output_body(WorkspaceDigestSchema(many=True),)
39
             session=request.dbsession,
40
             session=request.dbsession,
40
             config=app_config,
41
             config=app_config,
41
         )
42
         )
43
+        
44
+        workspaces = wapi.get_all_for_user(request.candidate_user)
42
         return [
45
         return [
43
             WorkspaceInContext(workspace, request.dbsession, app_config)
46
             WorkspaceInContext(workspace, request.dbsession, app_config)
44
-            for workspace in wapi.get_all_for_user(request.candidate_user)
47
+            for workspace in workspaces
45
         ]
48
         ]
46
 
49
 
47
     def bind(self, configurator: Configurator) -> None:
50
     def bind(self, configurator: Configurator) -> None:

+ 14 - 10
tracim/views/core_api/workspace_controller.py View File

5
 
5
 
6
 from tracim.lib.core.userworkspace import RoleApi
6
 from tracim.lib.core.userworkspace import RoleApi
7
 from tracim.lib.utils.authorization import require_workspace_role
7
 from tracim.lib.utils.authorization import require_workspace_role
8
-from tracim.models.context_models import WorkspaceInContext, \
9
-    UserRoleWorkspaceInContext
8
+from tracim.models.context_models import WorkspaceInContext
9
+from tracim.models.context_models import UserRoleWorkspaceInContext
10
 from tracim.models.data import UserRoleInWorkspace
10
 from tracim.models.data import UserRoleInWorkspace
11
 
11
 
12
 try:  # Python 3.5+
12
 try:  # Python 3.5+
15
     from http import client as HTTPStatus
15
     from http import client as HTTPStatus
16
 
16
 
17
 from tracim import hapic, TracimRequest
17
 from tracim import hapic, TracimRequest
18
-from tracim.exceptions import NotAuthentificated, InsufficientUserProfile, \
19
-    WorkspaceNotFound
18
+from tracim.exceptions import NotAuthentificated
19
+from tracim.exceptions import InsufficientUserProfile
20
+from tracim.exceptions import WorkspaceNotFound
20
 from tracim.lib.core.user import UserApi
21
 from tracim.lib.core.user import UserApi
21
 from tracim.lib.core.workspace import WorkspaceApi
22
 from tracim.lib.core.workspace import WorkspaceApi
22
 from tracim.views.controllers import Controller
23
 from tracim.views.controllers import Controller
23
-from tracim.views.core_api.schemas import WorkspaceSchema, UserSchema, \
24
-    WorkspaceIdPathSchema, WorkspaceMemberSchema
25
-
24
+from tracim.views.core_api.schemas import WorkspaceSchema
25
+from tracim.views.core_api.schemas import UserSchema
26
+from tracim.views.core_api.schemas import WorkspaceIdPathSchema
27
+from tracim.views.core_api.schemas import WorkspaceMemberSchema
26
 
28
 
27
 class WorkspaceController(Controller):
29
 class WorkspaceController(Controller):
28
 
30
 
68
             session=request.dbsession,
70
             session=request.dbsession,
69
             config=app_config,
71
             config=app_config,
70
         )
72
         )
73
+        
74
+        roles = rapi.get_all_for_workspace(request.current_workspace)
71
         return [
75
         return [
72
             rapi.get_user_role_workspace_with_context(user_role)
76
             rapi.get_user_role_workspace_with_context(user_role)
73
-            for user_role in rapi.get_all_for_workspace(request.current_workspace)
77
+            for user_role in roles
74
         ]
78
         ]
75
 
79
 
76
     def bind(self, configurator: Configurator) -> None:
80
     def bind(self, configurator: Configurator) -> None:
77
         """
81
         """
78
-        Create all routes and views using pyramid configurator
79
-        for this controller
82
+        Create all routes and views using
83
+        pyramid configurator for this controller
80
         """
84
         """
81
 
85
 
82
         # Applications
86
         # Applications