Browse Source

[https://github.com/tracim/tracim/issues/813] added handling of roles in frontend and apps

Skylsmoi 9 months ago
parent
commit
98c0f4d95c

+ 4 - 2
frontend/src/appFactory.js View File

@@ -4,8 +4,10 @@ import i18n from './i18n.js'
4 4
 
5 5
 export function appFactory (WrappedComponent) {
6 6
   return class AppFactory extends React.Component {
7
-    renderAppFeature = (appConfig, user, content) => GLOBAL_renderAppFeature({
8
-      loggedUser: user.logged ? user : {},
7
+    renderAppFeature = (appConfig, user, idRoleUserWorkspace, content) => GLOBAL_renderAppFeature({
8
+      loggedUser: user.logged
9
+        ? {...user, idRoleUserWorkspace}
10
+        : {},
9 11
       config: {
10 12
         ...appConfig,
11 13
         domContainer: 'appFeatureContainer',

+ 40 - 28
frontend/src/component/Workspace/BtnExtandedAction.jsx View File

@@ -18,23 +18,29 @@ const ExtandedAction = props => {
18 18
       </button>
19 19
 
20 20
       <div className='extandedaction__subdropdown dropdown-menu' aria-labelledby='dropdownMenuButton'>
21
-        <div className='subdropdown__item dropdown-item d-flex align-items-center' onClick={props.onClickExtendedAction.edit}>
22
-          <div className='subdropdown__item__icon mr-3'>
23
-            <i className='fa fa-fw fa-pencil' />
24
-          </div>
25
-          <div className='subdropdown__item__text'>
26
-            {props.t('Edit')}
27
-          </div>
28
-        </div>
21
+        {props.idRoleUserWorkspace >= 2 &&
22
+          <div className='subdropdown__item dropdown-item d-flex align-items-center' onClick={props.onClickExtendedAction.edit}>
23
+            <div className='subdropdown__item__icon mr-3'>
24
+              <i className='fa fa-fw fa-pencil' />
25
+            </div>
29 26
 
30
-        <div className='subdropdown__item dropdown-item d-flex align-items-center' onClick={props.onClickExtendedAction.move}>
31
-          <div className='subdropdown__item__icon mr-3'>
32
-            <i className='fa fa-fw fa-arrows-alt' />
27
+            <div className='subdropdown__item__text'>
28
+              {props.t('Edit')}
29
+            </div>
33 30
           </div>
34
-          <div className='subdropdown__item__text'>
35
-            {props.t('Move')}
31
+        }
32
+
33
+        {props.idRoleUserWorkspace >= 4 &&
34
+          <div className='subdropdown__item dropdown-item d-flex align-items-center' onClick={props.onClickExtendedAction.move}>
35
+            <div className='subdropdown__item__icon mr-3'>
36
+              <i className='fa fa-fw fa-arrows-alt' />
37
+            </div>
38
+
39
+            <div className='subdropdown__item__text'>
40
+              {props.t('Move')}
41
+            </div>
36 42
           </div>
37
-        </div>
43
+        }
38 44
 
39 45
         {/* <div className='subdropdown__item dropdown-item d-flex align-items-center' onClick={props.onClickExtendedAction.download}>
40 46
           <div className='subdropdown__item__icon mr-3'>
@@ -45,23 +51,29 @@ const ExtandedAction = props => {
45 51
           </div>
46 52
         </div> */ }
47 53
 
48
-        <div className='subdropdown__item dropdown-item d-flex align-items-center' onClick={props.onClickExtendedAction.archive}>
49
-          <div className='subdropdown__item__icon mr-3'>
50
-            <i className='fa fa-fw fa-archive' />
51
-          </div>
52
-          <div className='subdropdown__item__text'>
53
-            {props.t('Archive')}
54
-          </div>
55
-        </div>
54
+        {props.idRoleUserWorkspace >= 4 &&
55
+          <div className='subdropdown__item dropdown-item d-flex align-items-center' onClick={props.onClickExtendedAction.archive}>
56
+            <div className='subdropdown__item__icon mr-3'>
57
+              <i className='fa fa-fw fa-archive' />
58
+            </div>
56 59
 
57
-        <div className='subdropdown__item dropdown-item d-flex align-items-center' onClick={props.onClickExtendedAction.delete}>
58
-          <div className='subdropdown__item__icon mr-3'>
59
-            <i className='fa fa-fw fa-trash-o' />
60
+            <div className='subdropdown__item__text'>
61
+              {props.t('Archive')}
62
+            </div>
60 63
           </div>
61
-          <div className='subdropdown__item__text'>
62
-            {props.t('Delete')}
64
+        }
65
+
66
+        {props.idRoleUserWorkspace >= 4 &&
67
+          <div className='subdropdown__item dropdown-item d-flex align-items-center' onClick={props.onClickExtendedAction.delete}>
68
+            <div className='subdropdown__item__icon mr-3'>
69
+              <i className='fa fa-fw fa-trash-o' />
70
+            </div>
71
+
72
+            <div className='subdropdown__item__text'>
73
+              {props.t('Delete')}
74
+            </div>
63 75
           </div>
64
-        </div>
76
+        }
65 77
 
66 78
       </div>
67 79
     </div>

+ 8 - 3
frontend/src/component/Workspace/ContentItem.jsx View File

@@ -19,9 +19,14 @@ const ContentItem = props => {
19 19
         </div>
20 20
       </div>
21 21
 
22
-      <div className='d-none d-md-flex'>
23
-        <BtnExtandedAction onClickExtendedAction={props.onClickExtendedAction} />
24
-      </div>
22
+      {props.idRoleUserWorkspace >= 2 &&
23
+        <div className='d-none d-md-flex'>
24
+          <BtnExtandedAction
25
+            idRoleUserWorkspace={props.idRoleUserWorkspace}
26
+            onClickExtendedAction={props.onClickExtendedAction}
27
+          />
28
+        </div>
29
+      }
25 30
 
26 31
       <div className={classnames('content__status')} style={{color: status.hexcolor}}>
27 32
         <div className='content__status__text d-none d-xl-flex align-items-center justify-content-between'>

+ 36 - 33
frontend/src/component/Workspace/Folder.jsx View File

@@ -30,6 +30,7 @@ class Folder extends React.Component {
30 30
       availableApp,
31 31
       folderData,
32 32
       // onClickItem,
33
+      idRoleUserWorkspace,
33 34
       onClickExtendedAction,
34 35
       onClickCreateContent,
35 36
       // onClickFolder,
@@ -54,43 +55,45 @@ class Folder extends React.Component {
54 55
           </div>
55 56
 
56 57
           <div className='folder__header__button'>
57
-
58
-            <div className='folder__header__button__addbtn'>
59
-              <button
60
-                className='addbtn__text btn btn-outline-primary dropdown-toggle'
61
-                type='button'
62
-                id='dropdownMenuButton'
63
-                data-toggle='dropdown'
64
-                aria-haspopup='true'
65
-                aria-expanded='false'
66
-                onClick={e => e.stopPropagation()}
67
-              >
68
-                {t('Create in folder...')}
69
-              </button>
70
-
71
-              <div className='addbtn__subdropdown dropdown-menu' aria-labelledby='dropdownMenuButton'>
72
-                <SubDropdownCreateButton
73
-                  idFolder={null}
74
-                  availableApp={availableApp}
75
-                  onClickCreateContent={onClickCreateContent}
76
-                />
77
-              </div>
78
-
79
-              <div className='d-none d-md-flex'>
80
-                <BtnExtandedAction onClickExtendedAction={{
81
-                  edit: e => onClickExtendedAction.edit(e, folderData),
82
-                  move: e => onClickExtendedAction.move(e, folderData),
83
-                  download: e => onClickExtendedAction.download(e, folderData),
84
-                  archive: e => onClickExtendedAction.archive(e, folderData),
85
-                  delete: e => onClickExtendedAction.delete(e, folderData)
86
-                }} />
58
+            {idRoleUserWorkspace >= 2 &&
59
+              <div className='folder__header__button__addbtn'>
60
+                <button
61
+                  className='addbtn__text btn btn-outline-primary dropdown-toggle'
62
+                  type='button'
63
+                  id='dropdownMenuButton'
64
+                  data-toggle='dropdown'
65
+                  aria-haspopup='true'
66
+                  aria-expanded='false'
67
+                  onClick={e => e.stopPropagation()}
68
+                >
69
+                  {t('Create in folder...')}
70
+                </button>
71
+
72
+                <div className='addbtn__subdropdown dropdown-menu' aria-labelledby='dropdownMenuButton'>
73
+                  <SubDropdownCreateButton
74
+                    idFolder={null}
75
+                    availableApp={availableApp}
76
+                    onClickCreateContent={onClickCreateContent}
77
+                  />
78
+                </div>
79
+
80
+                <div className='d-none d-md-flex'>
81
+                  <BtnExtandedAction
82
+                    idRoleUserWorkspace={idRoleUserWorkspace}
83
+                    onClickExtendedAction={{
84
+                      edit: e => onClickExtendedAction.edit(e, folderData),
85
+                      move: e => onClickExtendedAction.move(e, folderData),
86
+                      download: e => onClickExtendedAction.download(e, folderData),
87
+                      archive: e => onClickExtendedAction.archive(e, folderData),
88
+                      delete: e => onClickExtendedAction.delete(e, folderData)
89
+                    }}
90
+                  />
91
+                </div>
87 92
               </div>
88
-
89
-            </div>
93
+            }
90 94
           </div>
91 95
 
92 96
           <div className='folder__header__status' />
93
-
94 97
         </div>
95 98
 
96 99
         <div className='folder__content'>

+ 16 - 2
frontend/src/component/Workspace/OpenContentApp.jsx View File

@@ -2,11 +2,22 @@ import React from 'react'
2 2
 import { connect } from 'react-redux'
3 3
 import { withRouter } from 'react-router'
4 4
 import appFactory from '../../appFactory.js'
5
+import { ROLE, findIdRoleUserWorkspace } from '../../helper.js'
5 6
 
6 7
 // @FIXME Côme - 2018/07/31 - should this be in a component like AppFeatureManager ?
7 8
 export class OpenContentApp extends React.Component {
8 9
   openContentApp = () => {
9
-    const { idWorkspace, appOpenedType, user, workspaceContentList, contentType, renderAppFeature, dispatchCustomEvent, match } = this.props
10
+    const {
11
+      idWorkspace,
12
+      appOpenedType,
13
+      user,
14
+      currentWorkspace,
15
+      workspaceContentList,
16
+      contentType,
17
+      renderAppFeature,
18
+      dispatchCustomEvent,
19
+      match
20
+    } = this.props
10 21
 
11 22
     if (isNaN(idWorkspace) || idWorkspace === -1) return
12 23
 
@@ -30,6 +41,7 @@ export class OpenContentApp extends React.Component {
30 41
         renderAppFeature(
31 42
           contentType.find(ct => ct.slug === contentToOpen.type),
32 43
           user,
44
+          findIdRoleUserWorkspace(user.user_id, currentWorkspace.memberList, ROLE),
33 45
           contentToOpen
34 46
         )
35 47
         this.props.updateAppOpenedType(contentToOpen.type)
@@ -54,5 +66,7 @@ export class OpenContentApp extends React.Component {
54 66
   }
55 67
 }
56 68
 
57
-const mapStateToProps = ({ user, workspaceContentList, contentType }) => ({ user, workspaceContentList, contentType })
69
+const mapStateToProps = ({ user, currentWorkspace, workspaceContentList, contentType }) => ({
70
+  user, currentWorkspace, workspaceContentList, contentType
71
+})
58 72
 export default withRouter(connect(mapStateToProps)(appFactory(OpenContentApp)))

+ 34 - 18
frontend/src/container/WorkspaceContent.jsx View File

@@ -2,7 +2,7 @@ import React from 'react'
2 2
 import { connect } from 'react-redux'
3 3
 import { withRouter, Route } from 'react-router-dom'
4 4
 import appFactory from '../appFactory.js'
5
-import { PAGE } from '../helper.js'
5
+import { PAGE, ROLE, findIdRoleUserWorkspace } from '../helper.js'
6 6
 import Folder from '../component/Workspace/Folder.jsx'
7 7
 import ContentItem from '../component/Workspace/ContentItem.jsx'
8 8
 import ContentItemHeader from '../component/Workspace/ContentItemHeader.jsx'
@@ -16,6 +16,7 @@ import {
16 16
 } from 'tracim_frontend_lib'
17 17
 import {
18 18
   getWorkspaceContentList,
19
+  getWorkspaceMemberList,
19 20
   getFolderContent,
20 21
   putWorkspaceContentArchived,
21 22
   putWorkspaceContentDeleted
@@ -24,7 +25,8 @@ import {
24 25
   newFlashMessage,
25 26
   setWorkspaceContentList,
26 27
   setWorkspaceContentArchived,
27
-  setWorkspaceContentDeleted
28
+  setWorkspaceContentDeleted,
29
+  setWorkspaceMemberList
28 30
 } from '../action-creator.sync.js'
29 31
 
30 32
 const qs = require('query-string')
@@ -101,12 +103,16 @@ class WorkspaceContent extends React.Component {
101 103
   }
102 104
 
103 105
   loadContentList = async idWorkspace => {
104
-    const { user, location, dispatch } = this.props
106
+    const { user, dispatch } = this.props
105 107
 
106 108
     const wsContent = await dispatch(getWorkspaceContentList(user, idWorkspace, 0))
109
+    const wsMember = await dispatch(getWorkspaceMemberList(user, idWorkspace))
107 110
 
108
-    if (wsContent.status === 200) dispatch(setWorkspaceContentList(wsContent.json, qs.parse(location.search).type))
111
+    if (await wsContent.status === 200) dispatch(setWorkspaceContentList(wsContent.json))
109 112
     else dispatch(newFlashMessage('Error while loading workspace', 'danger'))
113
+
114
+    if (await wsMember.status === 200) dispatch(setWorkspaceMemberList(wsMember.json))
115
+    else dispatch(newFlashMessage('Error while loading members list', 'warning'))
110 116
   }
111 117
 
112 118
   handleClickContentItem = content => {
@@ -171,7 +177,7 @@ class WorkspaceContent extends React.Component {
171 177
   handleUpdateAppOpenedType = openedAppType => this.setState({appOpenedType: openedAppType})
172 178
 
173 179
   render () {
174
-    const { workspaceContentList, contentType } = this.props
180
+    const { user, currentWorkspace, workspaceContentList, contentType } = this.props
175 181
 
176 182
     const filterWorkspaceContent = (contentList, filter) => {
177 183
       return filter.length === 0
@@ -188,6 +194,8 @@ class WorkspaceContent extends React.Component {
188 194
       ? filterWorkspaceContent(workspaceContentList, urlFilter ? [urlFilter] : [])
189 195
       : []
190 196
 
197
+    const idRoleUserWorkspace = findIdRoleUserWorkspace(user.user_id, currentWorkspace.memberList, ROLE)
198
+
191 199
     return (
192 200
       <div className='WorkspaceContent' style={{width: '100%'}}>
193 201
         <OpenContentApp
@@ -212,12 +220,14 @@ class WorkspaceContent extends React.Component {
212 220
             title='Liste des Contenus'
213 221
             subtitle={workspaceContentList.label ? workspaceContentList.label : ''}
214 222
           >
215
-            <DropdownCreateButton
216
-              parentClass='workspace__header__btnaddcontent'
217
-              idFolder={null} // null because it is workspace root content
218
-              onClickCreateContent={this.handleClickCreateContent}
219
-              availableApp={contentType.filter(ct => ct.slug !== 'comment')} // @FIXME: Côme - 2018/08/21 - should use props.appList
220
-            />
223
+            {idRoleUserWorkspace >= 2 &&
224
+              <DropdownCreateButton
225
+                parentClass='workspace__header__btnaddcontent'
226
+                idFolder={null} // null because it is workspace root content
227
+                onClickCreateContent={this.handleClickCreateContent}
228
+                availableApp={contentType.filter(ct => ct.slug !== 'comment')} // @FIXME: Côme - 2018/08/21 - should use props.appList
229
+              />
230
+            }
221 231
           </PageTitle>
222 232
 
223 233
           <PageContent parentClass='workspace__content'>
@@ -230,6 +240,7 @@ class WorkspaceContent extends React.Component {
230 240
                     availableApp={contentType.filter(ct => ct.slug !== 'comment')} // @FIXME: Côme - 2018/08/21 - should use props.appList
231 241
                     folderData={c}
232 242
                     onClickItem={this.handleClickContentItem}
243
+                    idRoleUserWorkspace={idRoleUserWorkspace}
233 244
                     onClickExtendedAction={{
234 245
                       edit: this.handleClickEditContentItem,
235 246
                       move: this.handleClickMoveContentItem,
@@ -251,6 +262,7 @@ class WorkspaceContent extends React.Component {
251 262
                     statusSlug={c.statusSlug}
252 263
                     contentType={contentType.length ? contentType.find(ct => ct.slug === c.type) : null}
253 264
                     onClickItem={() => this.handleClickContentItem(c)}
265
+                    idRoleUserWorkspace={idRoleUserWorkspace}
254 266
                     onClickExtendedAction={{
255 267
                       edit: e => this.handleClickEditContentItem(e, c),
256 268
                       move: e => this.handleClickMoveContentItem(e, c),
@@ -266,12 +278,14 @@ class WorkspaceContent extends React.Component {
266 278
               )}
267 279
             </div>
268 280
 
269
-            <DropdownCreateButton
270
-              customClass='workspace__content__button'
271
-              idFolder={null}
272
-              onClickCreateContent={this.handleClickCreateContent}
273
-              availableApp={contentType.filter(ct => ct.slug !== 'comment')} // @FIXME: Côme - 2018/08/21 - should use props.appList
274
-            />
281
+            {idRoleUserWorkspace >= 2 &&
282
+              <DropdownCreateButton
283
+                customClass='workspace__content__button'
284
+                idFolder={null}
285
+                onClickCreateContent={this.handleClickCreateContent}
286
+                availableApp={contentType.filter(ct => ct.slug !== 'comment')} // @FIXME: Côme - 2018/08/21 - should use props.appList
287
+              />
288
+            }
275 289
           </PageContent>
276 290
 
277 291
         </PageWrapper>
@@ -280,5 +294,7 @@ class WorkspaceContent extends React.Component {
280 294
   }
281 295
 }
282 296
 
283
-const mapStateToProps = ({ user, workspaceContentList, workspaceList, contentType }) => ({ user, workspaceContentList, workspaceList, contentType })
297
+const mapStateToProps = ({ user, currentWorkspace, workspaceContentList, workspaceList, contentType }) => ({
298
+  user, currentWorkspace, workspaceContentList, workspaceList, contentType
299
+})
284 300
 export default withRouter(connect(mapStateToProps)(appFactory(WorkspaceContent)))

+ 44 - 6
frontend/src/helper.js View File

@@ -44,33 +44,71 @@ export const PAGE = {
44 44
 }
45 45
 
46 46
 export const ROLE = [{
47
-  id: 0,
47
+  id: 1,
48 48
   slug: 'reader',
49 49
   faIcon: 'eye',
50
-  hexcolor: '#15D948',
50
+  hexcolor: '#15d948',
51 51
   label: 'Reader'
52 52
 }, {
53
-  id: 1,
53
+  id: 2,
54 54
   slug: 'contributor',
55 55
   faIcon: 'pencil',
56
-  hexcolor: '#3145F7',
56
+  hexcolor: '#3145f7',
57 57
   label: 'Contributor'
58 58
 }, {
59
-  id: 2,
59
+  id: 4,
60 60
   slug: 'content-manager',
61 61
   faIcon: 'graduation-cap',
62 62
   hexcolor: '#f2af2d',
63 63
   label: 'Content manager'
64 64
 }, {
65
-  id: 3,
65
+  id: 8,
66 66
   slug: 'workspace-manager',
67 67
   faIcon: 'gavel',
68 68
   hexcolor: '#ed0007',
69 69
   label: 'Workspace manager'
70 70
 }]
71 71
 
72
+export const findIdRoleUserWorkspace = (idUser, memberList, roleList) => {
73
+  const myself = memberList.find(u => u.id === idUser) || {role: 'reader'}
74
+  return (roleList.find(r => myself.role === r.slug) || {id: 1}).id
75
+}
76
+
77
+// Côme - 2018/08/21 - useful ?
78
+export const ROLE2 = {
79
+  reader: {
80
+    id: 1,
81
+    sluf: 'reader',
82
+    faIcon: 'eye',
83
+    hexcolor: '#15D948',
84
+    label: 'Reader'
85
+  },
86
+  contributor: {
87
+    id: 2,
88
+    slug: 'contributor',
89
+    faIcon: 'pencil',
90
+    hexcolor: '#3145f7',
91
+    label: 'Contributor'
92
+  },
93
+  contentManager: {
94
+    id: 4,
95
+    slug: 'content-manager',
96
+    faIcon: 'graduation-cap',
97
+    hexcolor: '#f2af2d',
98
+    label: 'Content manager'
99
+  },
100
+  workspaceManager: {
101
+    id: 8,
102
+    slug: 'workspace-manager',
103
+    faIcon: 'gavel',
104
+    hexcolor: '#ed0007',
105
+    label: 'Workspace manager'
106
+  }
107
+}
108
+
72 109
 export const PROFILE = {
73 110
   ADMINISTRATOR: 'administrators',
111
+  MANAGER: 'managers',
74 112
   USER: 'users'
75 113
 }
76 114
 

+ 25 - 18
frontend_app_html-document/src/container/HtmlDocument.jsx View File

@@ -384,6 +384,7 @@ class HtmlDocument extends React.Component {
384 384
           customColor={config.hexcolor}
385 385
           faIcon={config.faIcon}
386 386
           title={content.label}
387
+          idRoleUserWorkspace={loggedUser.idRoleUserWorkspace}
387 388
           onClickCloseBtn={this.handleClickBtnCloseApp}
388 389
           onValidateChangeTitle={this.handleSaveEditTitle}
389 390
         />
@@ -395,11 +396,13 @@ class HtmlDocument extends React.Component {
395 396
         >
396 397
           <div /* this div in display flex, justify-content space-between */>
397 398
             <div className='d-flex'>
398
-              <NewVersionBtn
399
-                customColor={config.hexcolor}
400
-                onClickNewVersionBtn={this.handleClickNewVersion}
401
-                disabled={mode !== MODE.VIEW}
402
-              />
399
+              {loggedUser.idRoleUserWorkspace >= 2 &&
400
+                <NewVersionBtn
401
+                  customColor={config.hexcolor}
402
+                  onClickNewVersionBtn={this.handleClickNewVersion}
403
+                  disabled={mode !== MODE.VIEW}
404
+                />
405
+              }
403 406
 
404 407
               {mode === MODE.REVISION &&
405 408
                 <button
@@ -414,19 +417,23 @@ class HtmlDocument extends React.Component {
414 417
             </div>
415 418
 
416 419
             <div className='d-flex'>
417
-              <SelectStatus
418
-                selectedStatus={config.availableStatuses.find(s => s.slug === content.status)}
419
-                availableStatus={config.availableStatuses}
420
-                onChangeStatus={this.handleChangeStatus}
421
-                disabled={mode === MODE.REVISION}
422
-              />
423
-
424
-              <ArchiveDeleteContent
425
-                customColor={config.hexcolor}
426
-                onClickArchiveBtn={this.handleClickArchive}
427
-                onClickDeleteBtn={this.handleClickDelete}
428
-                disabled={mode === MODE.REVISION}
429
-              />
420
+              {loggedUser.idRoleUserWorkspace >= 2 &&
421
+                <SelectStatus
422
+                  selectedStatus={config.availableStatuses.find(s => s.slug === content.status)}
423
+                  availableStatus={config.availableStatuses}
424
+                  onChangeStatus={this.handleChangeStatus}
425
+                  disabled={mode === MODE.REVISION}
426
+                />
427
+              }
428
+
429
+              {loggedUser.idRoleUserWorkspace >= 4 &&
430
+                <ArchiveDeleteContent
431
+                  customColor={config.hexcolor}
432
+                  onClickArchiveBtn={this.handleClickArchive}
433
+                  onClickDeleteBtn={this.handleClickDelete}
434
+                  disabled={mode === MODE.REVISION}
435
+                />
436
+              }
430 437
             </div>
431 438
           </div>
432 439
         </PopinFixedOption>

+ 2 - 1
frontend_app_html-document/src/helper.js View File

@@ -73,7 +73,8 @@ export const debug = {
73 73
     email: 'osef@algoo.fr',
74 74
     lang: 'en',
75 75
     avatar_url: 'https://avatars3.githubusercontent.com/u/11177014?s=460&v=4',
76
-    auth: btoa(`${'admin@admin.admin'}:${'admin@admin.admin'}`)
76
+    auth: btoa(`${'admin@admin.admin'}:${'admin@admin.admin'}`),
77
+    idRoleUserWorkspace: 1
77 78
   },
78 79
   content: {
79 80
     author: {

+ 18 - 13
frontend_app_thread/src/container/Thread.jsx View File

@@ -270,6 +270,7 @@ class Thread extends React.Component {
270 270
           customColor={config.hexcolor}
271 271
           faIcon={config.faIcon}
272 272
           title={content.label}
273
+          idRoleUserWorkspace={loggedUser.idRoleUserWorkspace}
273 274
           onClickCloseBtn={this.handleClickBtnCloseApp}
274 275
           onValidateChangeTitle={this.handleSaveEditTitle}
275 276
         />
@@ -280,19 +281,23 @@ class Thread extends React.Component {
280 281
           i18n={i18n}
281 282
         >
282 283
           <div className='justify-content-end'>
283
-            <SelectStatus
284
-              selectedStatus={config.availableStatuses.find(s => s.slug === content.status)}
285
-              availableStatus={config.availableStatuses}
286
-              onChangeStatus={this.handleChangeStatus}
287
-              disabled={false}
288
-            />
289
-
290
-            <ArchiveDeleteContent
291
-              customColor={config.hexcolor}
292
-              onClickArchiveBtn={this.handleClickArchive}
293
-              onClickDeleteBtn={this.handleClickDelete}
294
-              disabled={false}
295
-            />
284
+            {loggedUser.idRoleUserWorkspace >= 2 &&
285
+              <SelectStatus
286
+                selectedStatus={config.availableStatuses.find(s => s.slug === content.status)}
287
+                availableStatus={config.availableStatuses}
288
+                onChangeStatus={this.handleChangeStatus}
289
+                disabled={false}
290
+              />
291
+            }
292
+
293
+            {loggedUser.idRoleUserWorkspace >= 4 &&
294
+              <ArchiveDeleteContent
295
+                customColor={config.hexcolor}
296
+                onClickArchiveBtn={this.handleClickArchive}
297
+                onClickDeleteBtn={this.handleClickDelete}
298
+                disabled={false}
299
+              />
300
+            }
296 301
           </div>
297 302
         </PopinFixedOption>
298 303
 

+ 3 - 1
frontend_app_thread/src/helper.js View File

@@ -54,7 +54,9 @@ export const debug = { // copied from html-document => outdated
54 54
     lastname: 'Stoilenom',
55 55
     email: 'osef@algoo.fr',
56 56
     avatar_url: 'https://avatars3.githubusercontent.com/u/11177014?s=460&v=4',
57
-    lang: 'en'
57
+    auth: btoa(`${'admin@admin.admin'}:${'admin@admin.admin'}`),
58
+    lang: 'en',
59
+    idRoleUserWorkspace: 1
58 60
   },
59 61
   content: {
60 62
     author: {

+ 11 - 7
frontend_lib/src/component/PopinFixed/PopinFixedHeader.jsx View File

@@ -27,7 +27,7 @@ class PopinFixedHeader extends React.Component {
27 27
   }
28 28
 
29 29
   render () {
30
-    const { customClass, customColor, faIcon, title, onClickCloseBtn } = this.props
30
+    const { customClass, customColor, faIcon, title, idRoleUserWorkspace, onClickCloseBtn } = this.props
31 31
 
32 32
     return (
33 33
       <div className={classnames('wsContentGeneric__header', `${customClass}__header`)} style={{backgroundColor: customColor}}>
@@ -42,12 +42,14 @@ class PopinFixedHeader extends React.Component {
42 42
           }
43 43
         </div>
44 44
 
45
-        <div
46
-          className={classnames('wsContentGeneric__header__edittitle', `${customClass}__header__changetitle`)}
47
-          onClick={this.handleClickChangeTitleBtn}
48
-        >
49
-          {this.state.editTitle ? <i className='fa fa-check' title='Valider le Titre' /> : <i className='fa fa-pencil' title='Modifier le Titre' />}
50
-        </div>
45
+        {idRoleUserWorkspace >= 2 &&
46
+          <div
47
+            className={classnames('wsContentGeneric__header__edittitle', `${customClass}__header__changetitle`)}
48
+            onClick={this.handleClickChangeTitleBtn}
49
+          >
50
+            {this.state.editTitle ? <i className='fa fa-check' title='Valider le Titre' /> : <i className='fa fa-pencil' title='Modifier le Titre' />}
51
+          </div>
52
+        }
51 53
 
52 54
         <div
53 55
           className={classnames('wsContentGeneric__header__close', `${customClass}__header__close`)}
@@ -68,6 +70,7 @@ PopinFixedHeader.propTypes = {
68 70
   customClass: PropTypes.string,
69 71
   customColor: PropTypes.string,
70 72
   title: PropTypes.string,
73
+  idRoleUserWorkspace: PropTypes.number,
71 74
   onValidateChangeTitle: PropTypes.func
72 75
 }
73 76
 
@@ -75,5 +78,6 @@ PopinFixedHeader.defaultProps = {
75 78
   customClass: '',
76 79
   customColor: '',
77 80
   title: '',
81
+  idRoleUserWorkspace: 1,
78 82
   onChangeTitle: () => {}
79 83
 }

+ 59 - 56
frontend_lib/src/component/Timeline/Timeline.jsx View File

@@ -105,65 +105,67 @@ class Timeline extends React.Component {
105 105
             <li style={{visibility: 'hidden'}} ref={el => { this.timelineBottom = el }} />
106 106
           </ul>
107 107
 
108
-          <form className={classnames(`${props.customClass}__texteditor`, 'timeline__body__texteditor')}>
109
-            <div className={classnames(`${props.customClass}__texteditor__textinput`, 'timeline__body__texteditor__textinput')}>
110
-              <textarea
111
-                id='wysiwygTimelineComment'
112
-                placeholder='Votre message ...'
113
-                value={props.newComment}
114
-                onChange={props.onChangeNewComment}
115
-                disabled={props.disableComment}
116
-              />
117
-            </div>
118
-
119
-            <div className={classnames(`${props.customClass}__texteditor__wrapper`, 'timeline__body__texteditor__wrapper')}>
120
-              <div className={classnames(`${props.customClass}__texteditor__advancedtext`, 'timeline__body__texteditor__advancedtext')}>
121
-                <button
122
-                  type='button'
123
-                  className={classnames(
124
-                    `${props.customClass}__texteditor__advancedtext__btn timeline__body__texteditor__advancedtext__btn btn`
125
-                  )}
126
-                  onClick={props.onClickWysiwygBtn}
108
+          {props.loggedUser.idRoleUserWorkspace >= 2 &&
109
+            <form className={classnames(`${props.customClass}__texteditor`, 'timeline__body__texteditor')}>
110
+              <div className={classnames(`${props.customClass}__texteditor__textinput`, 'timeline__body__texteditor__textinput')}>
111
+                <textarea
112
+                  id='wysiwygTimelineComment'
113
+                  placeholder='Votre message ...'
114
+                  value={props.newComment}
115
+                  onChange={props.onChangeNewComment}
127 116
                   disabled={props.disableComment}
128
-                  style={{
129
-                    backgroundColor: 'transparent',
130
-                    color: '#333',
131
-                    borderColor: props.customColor,
132
-                    ':hover': {
133
-                      backgroundColor: props.customColor,
134
-                      color: '#fdfdfd'
135
-                    }
136
-                  }}
137
-                  key={'timeline__comment__advancedtext'}
138
-                >
139
-                  {props.wysiwyg ? 'Texte simple' : 'Texte riche'}
140
-                </button>
117
+                />
141 118
               </div>
142 119
 
143
-              <div className={classnames(`${props.customClass}__texteditor__submit`, 'timeline__body__texteditor__submit')}>
144
-                <button
145
-                  type='button'
146
-                  className={classnames(`${props.customClass}__texteditor__submit__btn`, 'timeline__body__texteditor__submit__btn btn')}
147
-                  onClick={props.onClickValidateNewCommentBtn}
148
-                  disabled={props.disableComment}
149
-                  style={{
150
-                    backgroundColor: props.customColor,
151
-                    color: '#fdfdfd',
152
-                    ':hover': {
153
-                      backgroundColor: color(props.customColor).darken(0.15).hexString()
154
-                    }
155
-                  }}
156
-                  key={'timeline__comment__send'}
157
-                >
158
-                  Envoyer
159
-                  <div
160
-                    className={classnames(`${props.customClass}__texteditor__submit__btn__icon`, 'timeline__body__texteditor__submit__btn__icon')}>
161
-                    <i className='fa fa-paper-plane-o' />
162
-                  </div>
163
-                </button>
120
+              <div className={classnames(`${props.customClass}__texteditor__wrapper`, 'timeline__body__texteditor__wrapper')}>
121
+                <div className={classnames(`${props.customClass}__texteditor__advancedtext`, 'timeline__body__texteditor__advancedtext')}>
122
+                  <button
123
+                    type='button'
124
+                    className={classnames(
125
+                      `${props.customClass}__texteditor__advancedtext__btn timeline__body__texteditor__advancedtext__btn btn`
126
+                    )}
127
+                    onClick={props.onClickWysiwygBtn}
128
+                    disabled={props.disableComment}
129
+                    style={{
130
+                      backgroundColor: 'transparent',
131
+                      color: '#333',
132
+                      borderColor: props.customColor,
133
+                      ':hover': {
134
+                        backgroundColor: props.customColor,
135
+                        color: '#fdfdfd'
136
+                      }
137
+                    }}
138
+                    key={'timeline__comment__advancedtext'}
139
+                  >
140
+                    {props.wysiwyg ? 'Texte simple' : 'Texte riche'}
141
+                  </button>
142
+                </div>
143
+
144
+                <div className={classnames(`${props.customClass}__texteditor__submit`, 'timeline__body__texteditor__submit')}>
145
+                  <button
146
+                    type='button'
147
+                    className={classnames(`${props.customClass}__texteditor__submit__btn`, 'timeline__body__texteditor__submit__btn btn')}
148
+                    onClick={props.onClickValidateNewCommentBtn}
149
+                    disabled={props.disableComment}
150
+                    style={{
151
+                      backgroundColor: props.customColor,
152
+                      color: '#fdfdfd',
153
+                      ':hover': {
154
+                        backgroundColor: color(props.customColor).darken(0.15).hexString()
155
+                      }
156
+                    }}
157
+                    key={'timeline__comment__send'}
158
+                  >
159
+                    Envoyer
160
+                    <div
161
+                      className={classnames(`${props.customClass}__texteditor__submit__btn__icon`, 'timeline__body__texteditor__submit__btn__icon')}>
162
+                      <i className='fa fa-paper-plane-o' />
163
+                    </div>
164
+                  </button>
165
+                </div>
164 166
               </div>
165
-            </div>
166
-          </form>
167
+            </form>
168
+          }
167 169
         </div>
168 170
       </div>
169 171
     )
@@ -200,7 +202,8 @@ Timeline.defaultProps = {
200 202
   loggedUser: {
201 203
     id: '',
202 204
     name: '',
203
-    avatar: ''
205
+    avatar: '',
206
+    idRoleUserWorkspace: 1
204 207
   },
205 208
   timelineData: [],
206 209
   wysiwyg: false,