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
@@ -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(
{
@@ -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
@@ -15,6 +15,10 @@ module.exports = (sequelize, DataTypes) => {
active: {
type: DataTypes.INTEGER,
defaultValue: true
},
role: {
type: DataTypes.STRING,
defaultValue: 'member'
}
},
{ timestamps: true }
4 changes: 2 additions & 2 deletions api/src/routes/categoriesRouter.js
Original file line number Diff line number Diff line change
@@ -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
@@ -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 (
@@ -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 />
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
@@ -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({
@@ -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
@@ -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>
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