Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Member role add (fixes: #405) #406

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
70 changes: 48 additions & 22 deletions api/src/controllers/communityUserController.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
const { Op } = require('sequelize')
const db = require('../models')

// @desc Get the community-users
// @route GET /api/community-users
// @access Public

const getCommunityUsers = async (req, res) => {
try {
const data = await db.CommunityUser.findAll()
res.json({
data
})
} catch (error) {
res.status(400).json({ error })
}
}

// @desc follow community
// @route POST /api/community-users/follow
// @access Public
Expand Down Expand Up @@ -82,31 +67,72 @@ const followCommunity = async (req, res) => {

const getAllMembers = async (req, res) => {
try {
const data = await db.CommunityUser.findAll(
const communityId = req.params.id
const member = await db.CommunityUser.findOne({ where: { userId: req.user.id, communityId }, attributes: ['role'] })

if (member.dataValues.role === 'manager') {
const data = await db.CommunityUser.findAll(
{
where: { communityId: req.params.id, active: true },
attributes: ['id', 'userId', 'role'],
include: [{
model: db.User,
attributes: ['firstName', 'lastName', 'email', 'phone', 'dateOfBirth']
}],
required: true
}
)

// flattening the array to show only one object
const newArray = data.map(item => {
const { userId, role, id } = item.dataValues
return { id, userId, role, ...item.user.dataValues }
})

res.json({
results: newArray
})
return
}

const newData = await db.CommunityUser.findAll(
{
where: { communityId: req.params.id, active: true },
attributes: ['userId'],
where: { communityId, active: true },
attributes: ['userId', 'role'],
include: [{
model: db.User,
attributes: ['firstName']
}],
required: true
}
)
res.json({
data
return res.json({
results: newData
})
} catch (error) {
res.status(400).json({ error })
}
}

// @desc Update the community users
// @route PUT /api/community-users/:memberId/community/:id/
// @access Public

const updateMemberRole = async (req, res) => {
try {
const { role } = req.body
await db.CommunityUser.update({ role }, { where: { id: parseInt(req.params.memberId) } })
res.json({ message: 'Successfully role updated' })
} catch (error) {
res.status(400).json({ error })
}
}

// @desc Search Name
// @route POST /api/news/community/:id/search
// @access Private
const searchMemberName = (req, res) => {
const { name } = req.query
const order = req.query.order || 'ASC'

db.CommunityUser.findAll(
{
Expand All @@ -129,4 +155,4 @@ const searchMemberName = (req, res) => {
.catch(err => res.json({ error: err }).status(400))
}

module.exports = { getCommunityUsers, followCommunity, getAllMembers, searchMemberName }
module.exports = { followCommunity, getAllMembers, searchMemberName, updateMemberRole }
49 changes: 41 additions & 8 deletions api/src/middleware/permission.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,48 @@
const permit = (role) => {
return (req, res, next) => {
if (checkRole(req, role)) {
next()
} else {
res.json({ error: 'Sorry, You don\'t have permission' })
const db = require('../models')

const permit = (category, roles) => {
return async (req, res, next) => {

switch(category) {
case 'community-member':
checkMemberRoles(roles, next, res, req)
break;
case 'user':
checkUserRoles(roles, next, res, req)
break;
default:
res.json({ error: 'Sorry, You don\'t have permission' })
}
// // getting member role
// const member = await db.CommunityUser.findOne({ where: { userId: req.user.id, communityId: req.params.id }, attributes: ['role'] })

// if (member.dataValues.role) {
// checkMemberRoles(roles, member, next, res)
// } else {
// checkUserRoles(roles, next, res, req)
// }
}
}

function checkRole (req, role) {
return role.some(el => el === req.user.role)
const checkRole = (roles, dbRole) => {
return roles.includes(dbRole)
}

const checkMemberRoles = async (roles, next, res, req) => {
const member = await db.CommunityUser.findOne({ where: { userId: req.user.id, communityId: req.params.id }, attributes: ['role'] })
if (checkRole(roles, member.dataValues.role)) {
next()
} else {
res.json({ error: 'Sorry, You don\'t have permission' })
}
}

const checkUserRoles = (roles, next, res, req) => {
if (checkRole(roles, req.user.role)) {
next()
} else {
res.json({ error: 'Sorry, You don\'t have permission' })
}
}

module.exports = permit
14 changes: 14 additions & 0 deletions api/src/migrations/20210728085949-alter_community_user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use strict'

module.exports = {
up: async (queryInterface, Sequelize) => {
queryInterface.addColumn('communities_users', 'role', {
type: Sequelize.STRING,
defaultValue: 'member'
})
},

down: async (queryInterface, Sequelize) => {
queryInterface.removeColumn('communities_users', 'role')
}
}
4 changes: 4 additions & 0 deletions api/src/models/communityUserModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ module.exports = (sequelize, DataTypes) => {
active: {
type: DataTypes.INTEGER,
defaultValue: true
},
role: {
type: DataTypes.STRING,
defaultValue: 'member'
}
},
{ timestamps: true }
Expand Down
4 changes: 2 additions & 2 deletions api/src/routes/categoriesRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const {
} = require('../controllers/categoryController')
const permit = require('../middleware/permission')

router.route('/').get(protect, getCategories).post(protect, permit(['sysadmin']), addCategory)
router.route('/:id').get(getSingleCategory).put(protect, permit(['sysadmin']), updateCategory).delete(protect, permit(['sysadmin']), deleteCategory)
router.route('/').get(protect, getCategories).post(protect, permit('user', ['sysadmin']), addCategory)
router.route('/:id').get(getSingleCategory).put(protect, permit('user', ['sysadmin']), updateCategory).delete(protect, permit(['sysadmin']), deleteCategory)

module.exports = router
8 changes: 4 additions & 4 deletions api/src/routes/communityUserRouter.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
const { getCommunityUsers, followCommunity, getAllMembers, searchMemberName } = require('../controllers/communityUserController')
const { followCommunity, getAllMembers, searchMemberName, updateMemberRole } = require('../controllers/communityUserController')
const protect = require('../middleware/authMiddleware')
const permit = require('../middleware/permission')
const router = require('express').Router()

router.get('/', getCommunityUsers)
router.post('/follow', protect, followCommunity)
router.get('/community/:id', getAllMembers)
router.get('/community/:id', protect, permit('community-member', ['manager','member']), getAllMembers)
router.get('/community/:id/search', searchMemberName)
// router.put('/:id', updateCommunityUsers);
router.put('/:memberId/community/:id/', protect, permit('community-member', ['manager']), updateMemberRole)

module.exports = router
2 changes: 2 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import AddTest from './screens/addTest/AddTest'
import LogoutUser from './screens/logoutUser/LogoutUser'
import Category from './screens/category/Category'
import PageNotFound from './screens/pageNotFound/PageNotFound'
import CommunityMemberAdmin from './screens/admin/CommunityMemberAdmin'

function App () {
return (
Expand All @@ -78,6 +79,7 @@ function App () {
<PrivateRoute component={CommunityNewsViewPage} path='/community-page-news-view' exact />
<PrivateRoute component={AllCommunitiesCard} path='/community-switching' exact />
<PrivateRoute component={CommunityMembers} path='/community-members/:id' exact />
<PrivateRoute component={CommunityMemberAdmin} path='/admin/community-members' exact />
<PrivateRoute component={CommunityMembersProfile} path='/community-members-profile/:id' exact />
<PrivateRoute component={CommunityGroup} path='/community-group/:id' exact />
<PrivateRoute component={CommunityGroup} path='/your-community-group/:id' exact />
Expand Down
35 changes: 31 additions & 4 deletions src/actions/memberActions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { getApi } from '../utils/apiFunc'
import { getApi, putApi } from '../utils/apiFunc'
import {
MEMBER_ACCESS_FAIL,
MEMBER_ACCESS_REQUEST,
MEMBER_ACCESS_SUCCESS,
MEMBER_LIST_FAIL, MEMBER_LIST_REQUEST, MEMBER_LIST_SUCCESS,
MEMBER_SEARCH_FAIL, MEMBER_SEARCH_REQUEST,
MEMBER_SEARCH_SUCCESS
Expand Down Expand Up @@ -39,13 +42,12 @@ export const searchMembers = (search) => async (
) => {
try {
dispatch({ type: MEMBER_SEARCH_REQUEST })
const { data } = await getApi(
await getApi(
dispatch,
`${process.env.REACT_APP_API_BASE_URL}/api/communities-users/community/${currentCommunity.id}/search?name=${search}`
)
dispatch({
type: MEMBER_SEARCH_SUCCESS,
payload: data.member
type: MEMBER_SEARCH_SUCCESS
})
} catch (error) {
dispatch({
Expand All @@ -57,3 +59,28 @@ export const searchMembers = (search) => async (
})
}
}

export const allowAccess = (id, role) => async (
dispatch
) => {
try {
dispatch({ type: MEMBER_ACCESS_REQUEST })
const { data } = await putApi(
dispatch,
`${process.env.REACT_APP_API_BASE_URL}/api/communities-users/${id}/community/${currentCommunity.id}`,
{ role }
)
dispatch({
type: MEMBER_ACCESS_SUCCESS,
payload: data
})
} catch (error) {
dispatch({
type: MEMBER_ACCESS_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message
})
}
}
2 changes: 1 addition & 1 deletion src/components/cardImage/CardImage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function CardImage ({ data = [], className }) {
<img src={profile?.attachments || '/img/profile-image.svg'} alt='group-profile' />
</div>
<div className='profile-card-name'>
<div className='card-name ibmplexsans-semi-bold-quarter-spanish-white-16px'>{profile?.user.firstName || 'anonymous'} </div>
<div className='card-name ibmplexsans-semi-bold-quarter-spanish-white-16px'>{profile.user !== undefined ? (profile.user.firstName || 'anonymous') : (profile.firstName || 'anonymous')} </div>
</div>
{Follow()}
</div>
Expand Down
43 changes: 43 additions & 0 deletions src/components/dropDown/DropDown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { useState } from 'react'
import { useEffect } from 'react'
import { useRef } from 'react'
import useHideOnClick from '../../utils/useHideOnClick'
import './DropDown.scss'

const DropDown = ({ data, title, getRole, id, role }) => {
const [active, setActive] = useState()
const domNode = useHideOnClick(() => {
setActive(false)
})

function clickHandler (item) {
setActive(false)
getRole(item, id)
}

function showDropdown () {
setActive(!active)
}

return (
<div className='dropdown-wrapper' ref={domNode}>
<div onClick={showDropdown} className='dropdown-title'>
<span>{title}</span>
<img
className='dropdown-icon'
src='/img/chevron-right-outline.svg'
/>
</div>
{active && (
<ul className='dropdown-lists'>
{data.length > 0 &&
data.filter(el => el !== role).map((item) => (
<li onClick={() => clickHandler(item)}>{item}</li>
))}
</ul>
)}
</div>
)
}

export default DropDown
45 changes: 45 additions & 0 deletions src/components/dropDown/DropDown.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
.dropdown-wrapper {
width: 200px;
position: relative;

.dropdown-title {
color: var(--primary-white);
display: flex;
justify-content: space-between;
align-items: center;
top: 10px;
z-index: 999;
border: 1px solid var(--primary-white);
cursor: pointer;
padding: 11px;
width: 100%;
text-transform: capitalize;
border-radius: 4px;
}

.dropdown-lists {
color: var(--primary-white);
position: absolute;
top: 2.3em;
background: var(--background-color-light);
margin-top: 0.5em;
border: 1px solid var(--dropdowns);
border-radius: 4px;
z-index: 2000;
width: 100%;
list-style: none;

li {
padding: 1em 2em;
width: 100%;
cursor: pointer;
background: var(--background-color);
color: #ffff;
text-transform: capitalize;

&:hover {
background: var(--primary-color);
}
}
}
}
Loading