Browse Source

merge with better_api_doc

Guénaël Muller 6 years ago
parent
commit
9229fcd973

+ 0 - 267
development.ini.old View File

@@ -1,267 +0,0 @@
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

+ 7 - 3
tracim/exceptions.py View File

@@ -93,13 +93,17 @@ class WrongUserPassword(TracimException):
93 93
     pass
94 94
 
95 95
 
96
-class UserNotExist(TracimException):
96
+class ContentStatusNotExist(TracimError):
97 97
     pass
98 98
 
99 99
 
100
-class ContentStatusNotExist(TracimError):
100
+class ContentTypeNotExist(TracimError):
101 101
     pass
102 102
 
103 103
 
104
-class ContentTypeNotExist(TracimError):
104
+class UserDoesNotExist(TracimException):
105
+    pass
106
+
107
+
108
+class UserNotFoundInTracimRequest(TracimException):
105 109
     pass

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

@@ -17,7 +17,6 @@ class GroupApi(object):
17 17
             session: Session,
18 18
             current_user: typing.Optional[User],
19 19
             config: CFG
20
-
21 20
     ):
22 21
         self._user = current_user
23 22
         self._session = session

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

@@ -7,9 +7,10 @@ import typing as typing
7 7
 from sqlalchemy.orm import Session
8 8
 
9 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 12
 from sqlalchemy.orm.exc import NoResultFound
12
-from tracim.exceptions import WrongUserPassword, UserNotExist
13
+from tracim.exceptions import WrongUserPassword, UserDoesNotExist
13 14
 from tracim.exceptions import AuthenticationFailed
14 15
 from tracim.models.context_models import UserInContext
15 16
 
@@ -48,8 +49,8 @@ class UserApi(object):
48 49
         """
49 50
         try:
50 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 54
         return user
54 55
 
55 56
     def get_one_by_email(self, email: str) -> User:
@@ -60,8 +61,8 @@ class UserApi(object):
60 61
         """
61 62
         try:
62 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 66
         return user
66 67
 
67 68
     # FIXME - G.M - 24-04-2018 - Duplicate method with get_one.
@@ -73,7 +74,7 @@ class UserApi(object):
73 74
         Get current_user
74 75
         """
75 76
         if not self._user:
76
-            raise UserNotExist()
77
+            raise UserDoesNotExist('There is no current user')
77 78
         return self._user
78 79
 
79 80
     def get_all(self) -> typing.Iterable[User]:
@@ -102,9 +103,9 @@ class UserApi(object):
102 103
             if user.validate_password(password):
103 104
                 return user
104 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 110
     # Actions
110 111
 

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

@@ -7,7 +7,8 @@ from tracim.models.context_models import UserRoleWorkspaceInContext
7 7
 __author__ = 'damien'
8 8
 
9 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 12
 from tracim.models.data import Workspace
12 13
 from tracim.models.data import UserRoleInWorkspace
13 14
 from tracim.models.data import RoleType
@@ -73,15 +74,17 @@ class RoleApi(object):
73 74
 
74 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 83
         self._session = session
81 84
         self._user = current_user
82 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 89
         :param user_id:
87 90
         :param workspace_id:
@@ -91,16 +94,16 @@ class RoleApi(object):
91 94
             filter(UserRoleInWorkspace.workspace_id == workspace_id).\
92 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 98
         return self._get_one_rsc(user_id, workspace_id).one()
96 99
 
97 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 107
     ) -> UserRoleInWorkspace:
105 108
         role = self.create_role()
106 109
         role.user_id = user.user_id
@@ -111,34 +114,38 @@ class RoleApi(object):
111 114
             self._session.flush()
112 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 118
         self._get_one_rsc(user_id, workspace_id).delete()
116 119
         if flush:
117 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 123
         return self._session.query(UserRoleInWorkspace)\
121 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 127
         return self._get_all_for_user(user.user_id).all()
125 128
 
126 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 133
         return self._get_all_for_user(user_id)\
131 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 140
         return self._session.query(UserRoleInWorkspace)\
135 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 144
         self._session.flush()
139 145
 
146
+    # TODO - G.M - 07-06-2018 - [Cleanup] Check if this method is already needed
140 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 151
         :return: list of DictLikeClass instances representing available Roles

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

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

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

@@ -100,4 +100,4 @@ def require_workspace_role(minimal_required_role):
100 100
             raise InsufficientUserWorkspaceRole()
101 101
 
102 102
         return wrapper
103
-    return decorator
103
+    return decorator

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

@@ -5,7 +5,10 @@ TracimRequest and related functions
5 5
 from pyramid.request import Request
6 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 12
 from tracim.exceptions import WorkspaceNotFound
10 13
 from tracim.exceptions import ImmutableAttribute
11 14
 from tracim.lib.core.user import UserApi
@@ -142,10 +145,10 @@ def get_candidate_user(
142 145
         if 'user_id' in request.matchdict:
143 146
             login = request.matchdict['user_id']
144 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 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 152
     return user
150 153
 
151 154
 
@@ -162,11 +165,10 @@ def get_auth_safe_user(
162 165
     try:
163 166
         login = request.authenticated_userid
164 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 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 172
     return user
171 173
 
172 174
 

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

@@ -25,7 +25,6 @@ class Application(object):
25 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 28
 # default apps
30 29
 calendar = Application(
31 30
     label='Calendar',
@@ -58,29 +57,30 @@ file = Application(
58 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 63
     icon='file-code',
65 64
     hexcolor='#f12d2d',
66 65
     is_active=True,
67 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 71
     label='Text Documents',  # TODO - G.M - 24-05-2018 - Check label
73
-    slug='contents/pagehtml',
72
+    slug='contents/htmlpage',
74 73
     icon='file-text-o',
75 74
     hexcolor='#3f52e3',
76 75
     is_active=True,
77 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 80
 # List of applications
81 81
 applications = [
82
-    pagehtml,
83
-    pagemarkdownplus,
82
+    htmlpage,
83
+    markdownpluspage,
84 84
     file,
85 85
     thread,
86 86
     calendar,

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

@@ -91,15 +91,19 @@ class Group(DeclarativeBase):
91 91
 class Profile(object):
92 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 108
     # TODO - G.M - 18-04-2018 [Cleanup] Drop this
105 109
     # _LABEL = [l_('Nobody'),

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

@@ -3,7 +3,7 @@ import typing
3 3
 from enum import Enum
4 4
 
5 5
 from tracim.exceptions import ContentStatusNotExist, ContentTypeNotExist
6
-from tracim.models.applications import pagehtml, file, thread, pagemarkdownplus
6
+from tracim.models.applications import htmlpage, file, thread, markdownpluspage
7 7
 
8 8
 
9 9
 ####
@@ -150,19 +150,19 @@ file_type = NewContentType(
150 150
     available_statuses=CONTENT_DEFAULT_STATUS,
151 151
 )
152 152
 
153
-pagemarkdownplus_type = NewContentType(
153
+markdownpluspage_type = NewContentType(
154 154
     slug='markdownpage',
155
-    icon=pagemarkdownplus.icon,
156
-    hexcolor=pagemarkdownplus.hexcolor,
155
+    icon=markdownpluspage.icon,
156
+    hexcolor=markdownpluspage.hexcolor,
157 157
     label='Rich Markdown File',
158 158
     creation_label='Create a Markdown document',
159 159
     available_statuses=CONTENT_DEFAULT_STATUS,
160 160
 )
161 161
 
162
-pagehtml_type = NewContentType(
162
+htmlpage_type = NewContentType(
163 163
     slug='page',
164
-    icon=pagehtml.icon,
165
-    hexcolor=pagehtml.hexcolor,
164
+    icon=htmlpage.icon,
165
+    hexcolor=htmlpage.hexcolor,
166 166
     label='Text Document',
167 167
     creation_label='Write a document',
168 168
     available_statuses=CONTENT_DEFAULT_STATUS,
@@ -181,8 +181,8 @@ folder_type = NewContentType(
181 181
 CONTENT_DEFAULT_TYPE = [
182 182
     thread_type,
183 183
     file_type,
184
-    pagemarkdownplus_type,
185
-    pagehtml_type,
184
+    markdownpluspage_type,
185
+    htmlpage_type,
186 186
     folder_type,
187 187
 ]
188 188
 
@@ -200,7 +200,7 @@ class ContentTypeLegacy(NewContentType):
200 200
 
201 201
     File = file_type.slug
202 202
     Thread = thread_type.slug
203
-    Page = pagehtml_type.slug
203
+    Page = htmlpage_type.slug
204 204
 
205 205
     def __init__(self, slug: str):
206 206
         for content_type in CONTENT_DEFAULT_TYPE:

+ 5 - 3
tracim/models/context_models.py View File

@@ -7,9 +7,10 @@ from sqlalchemy.orm import Session
7 7
 from tracim import CFG
8 8
 from tracim.models import User
9 9
 from tracim.models.auth import Profile
10
-from tracim.models.data import Workspace, UserRoleInWorkspace, Content
11
-from tracim.models.workspace_menu_entries import default_workspace_menu_entry, \
12
-    WorkspaceMenuEntry
10
+from tracim.models.data import Content
11
+from tracim.models.data import Workspace, UserRoleInWorkspace
12
+from tracim.models.workspace_menu_entries import default_workspace_menu_entry
13
+from tracim.models.workspace_menu_entries import WorkspaceMenuEntry
13 14
 
14 15
 
15 16
 class LoginCredentials(object):
@@ -37,6 +38,7 @@ class ContentFilter(object):
37 38
         self.show_deleted = bool(show_deleted)
38 39
         self.show_active = bool(show_active)
39 40
 
41
+
40 42
 class UserInContext(object):
41 43
     """
42 44
     Interface to get User data and User data related to context.

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

@@ -131,12 +131,13 @@ class UserRoleInWorkspace(DeclarativeBase):
131 131
     WORKSPACE_MANAGER = 8
132 132
 
133 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 142
     # LABEL = dict()
142 143
     # LABEL[0] = l_('N/A')

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

@@ -24,7 +24,6 @@ class WorkspaceMenuEntry(object):
24 24
         self.hexcolor = hexcolor
25 25
         self.icon = icon
26 26
 
27
-
28 27
 dashboard_menu_entry = WorkspaceMenuEntry(
29 28
   slug='dashboard',
30 29
   label='Dashboard',
@@ -40,7 +39,8 @@ all_content_menu_entry = WorkspaceMenuEntry(
40 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 44
 def default_workspace_menu_entry(
45 45
     workspace: Workspace,
46 46
 )-> typing.List[WorkspaceMenuEntry]:

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

@@ -25,14 +25,14 @@ class TestApplicationsEndpoint(FunctionalTest):
25 25
         res = res.json_body
26 26
         application = res[0]
27 27
         assert application['label'] == "Text Documents"
28
-        assert application['slug'] == 'contents/pagehtml'
28
+        assert application['slug'] == 'contents/htmlpage'
29 29
         assert application['icon'] == 'file-text-o'
30 30
         assert application['hexcolor'] == '#3f52e3'
31 31
         assert application['is_active'] is True
32 32
         assert 'config' in application
33 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 36
         assert application['icon'] == 'file-code'
37 37
         assert application['hexcolor'] == '#f12d2d'
38 38
         assert application['is_active'] is True

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

@@ -47,16 +47,16 @@ class TestUserWorkspaceEndpoint(FunctionalTest):
47 47
         assert sidebar_entry['icon'] == ""
48 48
 
49 49
         sidebar_entry = workspace['sidebar_entries'][2]
50
-        assert sidebar_entry['slug'] == 'contents/pagehtml'
50
+        assert sidebar_entry['slug'] == 'contents/htmlpage'
51 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 53
         assert sidebar_entry['hexcolor'] == "#3f52e3"
54 54
         assert sidebar_entry['icon'] == "file-text-o"
55 55
 
56 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 60
         assert sidebar_entry['hexcolor'] == "#f12d2d"
61 61
         assert sidebar_entry['icon'] == "file-code"
62 62
 

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

@@ -48,16 +48,16 @@ class TestWorkspaceEndpoint(FunctionalTest):
48 48
         assert sidebar_entry['icon'] == ""
49 49
 
50 50
         sidebar_entry = workspace['sidebar_entries'][2]
51
-        assert sidebar_entry['slug'] == 'contents/pagehtml'
51
+        assert sidebar_entry['slug'] == 'contents/htmlpage'
52 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 54
         assert sidebar_entry['hexcolor'] == "#3f52e3"
55 55
         assert sidebar_entry['icon'] == "file-text-o"
56 56
 
57 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 61
         assert sidebar_entry['hexcolor'] == "#f12d2d"
62 62
         assert sidebar_entry['icon'] == "file-code"
63 63
 

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

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

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

@@ -177,30 +177,24 @@ class WorkspaceMenuEntrySchema(marshmallow.Schema):
177 177
         description = 'Entry element of a workspace menu'
178 178
 
179 179
 
180
-class WorkspaceSchema(marshmallow.Schema):
180
+class WorkspaceDigestSchema(marshmallow.Schema):
181 181
     id = marshmallow.fields.Int(example=4)
182
-    slug = marshmallow.fields.String(example='intranet')
183 182
     label = marshmallow.fields.String(example='Intranet')
184
-    description = marshmallow.fields.String(example='All intranet data.')
185 183
     sidebar_entries = marshmallow.fields.Nested(
186 184
         WorkspaceMenuEntrySchema,
187 185
         many=True,
188 186
     )
189 187
 
190 188
     class Meta:
191
-        description = 'Full workspace informations'
189
+        description = 'Digest of workspace informations'
192 190
 
193 191
 
194
-class WorkspaceDigestSchema(marshmallow.Schema):
195
-    id = marshmallow.fields.Int(example=4)
196
-    label = marshmallow.fields.String(example='Intranet')
197
-    sidebar_entries = marshmallow.fields.Nested(
198
-        WorkspaceMenuEntrySchema,
199
-        many=True,
200
-    )
192
+class WorkspaceSchema(WorkspaceDigestSchema):
193
+    slug = marshmallow.fields.String(example='intranet')
194
+    description = marshmallow.fields.String(example='All intranet data.')
201 195
 
202 196
     class Meta:
203
-        description = 'Digest of workspace informations'
197
+        description = 'Full workspace informations'
204 198
 
205 199
 
206 200
 class WorkspaceMemberSchema(marshmallow.Schema):

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

@@ -11,13 +11,14 @@ except ImportError:
11 11
     from http import client as HTTPStatus
12 12
 
13 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 18
 from tracim.lib.core.workspace import WorkspaceApi
18 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 24
 class UserController(Controller):
@@ -25,7 +26,7 @@ class UserController(Controller):
25 26
     @hapic.with_api_doc()
26 27
     @hapic.handle_exception(NotAuthentificated, HTTPStatus.UNAUTHORIZED)
27 28
     @hapic.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
28
-    @hapic.handle_exception(UserNotExist, HTTPStatus.NOT_FOUND)
29
+    @hapic.handle_exception(UserDoesNotExist, HTTPStatus.NOT_FOUND)
29 30
     @require_same_user_or_profile(Group.TIM_ADMIN)
30 31
     @hapic.input_path(UserIdPathSchema())
31 32
     @hapic.output_body(WorkspaceDigestSchema(many=True),)
@@ -39,9 +40,11 @@ class UserController(Controller):
39 40
             session=request.dbsession,
40 41
             config=app_config,
41 42
         )
43
+        
44
+        workspaces = wapi.get_all_for_user(request.candidate_user)
42 45
         return [
43 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 50
     def bind(self, configurator: Configurator) -> None:

+ 19 - 18
tracim/views/core_api/workspace_controller.py View File

@@ -1,14 +1,6 @@
1 1
 import typing
2 2
 
3 3
 from pyramid.config import Configurator
4
-from sqlalchemy.orm.exc import NoResultFound
5
-
6
-from tracim.lib.core.content import ContentApi
7
-from tracim.lib.core.userworkspace import RoleApi
8
-from tracim.lib.utils.authorization import require_workspace_role
9
-from tracim.models.context_models import WorkspaceInContext, \
10
-    UserRoleWorkspaceInContext, ContentInContext
11
-from tracim.models.data import UserRoleInWorkspace
12 4
 
13 5
 try:  # Python 3.5+
14 6
     from http import HTTPStatus
@@ -16,15 +8,22 @@ except ImportError:
16 8
     from http import client as HTTPStatus
17 9
 
18 10
 from tracim import hapic, TracimRequest
19
-from tracim.exceptions import NotAuthentificated, InsufficientUserProfile, \
20
-    WorkspaceNotFound
21
-from tracim.lib.core.user import UserApi
22 11
 from tracim.lib.core.workspace import WorkspaceApi
12
+from tracim.lib.core.content import ContentApi
13
+from tracim.lib.core.userworkspace import RoleApi
14
+from tracim.lib.utils.authorization import require_workspace_role
15
+from tracim.models.data import UserRoleInWorkspace
16
+from tracim.models.context_models import UserRoleWorkspaceInContext
17
+from tracim.models.context_models import ContentInContext
18
+from tracim.exceptions import NotAuthentificated
19
+from tracim.exceptions import InsufficientUserProfile
20
+from tracim.exceptions import WorkspaceNotFound
23 21
 from tracim.views.controllers import Controller
24
-from tracim.views.core_api.schemas import WorkspaceSchema, UserSchema, \
25
-    WorkspaceIdPathSchema, WorkspaceMemberSchema, \
26
-    WorkspaceAndContentIdPathSchema, FilterContentQuerySchema, \
27
-    ContentDigestSchema
22
+from tracim.views.core_api.schemas import FilterContentQuerySchema
23
+from tracim.views.core_api.schemas import ContentDigestSchema
24
+from tracim.views.core_api.schemas import WorkspaceSchema
25
+from tracim.views.core_api.schemas import WorkspaceIdPathSchema
26
+from tracim.views.core_api.schemas import WorkspaceMemberSchema
28 27
 
29 28
 
30 29
 class WorkspaceController(Controller):
@@ -71,9 +70,11 @@ class WorkspaceController(Controller):
71 70
             session=request.dbsession,
72 71
             config=app_config,
73 72
         )
73
+        
74
+        roles = rapi.get_all_for_workspace(request.current_workspace)
74 75
         return [
75 76
             rapi.get_user_role_workspace_with_context(user_role)
76
-            for user_role in rapi.get_all_for_workspace(request.current_workspace)
77
+            for user_role in roles
77 78
         ]
78 79
 
79 80
     @hapic.with_api_doc()
@@ -114,8 +115,8 @@ class WorkspaceController(Controller):
114 115
 
115 116
     def bind(self, configurator: Configurator) -> None:
116 117
         """
117
-        Create all routes and views using pyramid configurator
118
-        for this controller
118
+        Create all routes and views using
119
+        pyramid configurator for this controller
119 120
         """
120 121
 
121 122
         # Workspace