Skip to content

Commit e96bb0a

Browse files
committed
Handled Enable / Disable of a control from RBAC Control panel
1 parent b6397d4 commit e96bb0a

File tree

13 files changed

+112
-34
lines changed

13 files changed

+112
-34
lines changed

client/public/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<title>React App</title>
2626
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
2727
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
28+
<link rel="stylesheet" href="styles.css">
2829
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
2930
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
3031
</head>

client/public/styles.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.disable-control {
2+
pointer-events: none;
3+
color: gray;
4+
}

client/src/App.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, { } from 'react';
22
import './App.css';
33
import { BrowserRouter as Router, Switch, Route, Link, Redirect, useHistory } from "react-router-dom";
44
import { useSelector, useDispatch } from 'react-redux';
5-
import { PostCreate, Posts, Home } from "./components/Posts";
5+
import { PostCreate, Posts, Home, PostDetail, PostEdit, PostDelete } from "./components/Posts";
66
import { Login } from "./components/Login";
77
import { Register } from "./components/Register";
88
import { Constants } from "./constants";
@@ -73,14 +73,17 @@ const App = () => {
7373
//console.log('userContext', userContext);
7474

7575
let links = [
76-
{ name: 'link-posts', url: '/posts', text: 'Posts', component: Posts },
77-
{ name: 'link-post-create', url: '/post-create', text: 'Create post', component: PostCreate },
78-
{ name: 'link-permission-create', url: '/permission-create', text: 'Create permission', component: PermissionCreate },
79-
{ name: 'link-permission-list', url: '/permission-list', text: 'List permissions', component: PermissionList },
80-
{ name: 'link-role-create', url: '/role-create', text: 'Create role', component: RoleCreate },
81-
{ name: 'link-role-list', url: '/role-list', text: 'List role', component: RoleList },
82-
{ name: 'link-resource-create', url: '/resource-create', text: 'Create resource', component: ResourceCreate },
83-
{ name: 'link-resource-list', url: '/resource-list', text: 'List resource', component: ResourceList },
76+
{ name: 'link-posts', url: '/posts', text: 'Posts', component: Posts, isRootMenu: true },
77+
{ name: 'link-post-create', url: '/post-create', text: 'Create post', component: PostCreate, isRootMenu: true },
78+
{ name: 'link-post-detail', url: '/post-detail/:id', text: 'Detail post', component: PostDetail },
79+
{ name: 'link-post-edit', url: '/post-edit/:id', text: 'Edit post', component: PostEdit },
80+
{ name: 'link-post-delete', url: '/post-delete/:id', text: 'Delete post', component: PostDelete },
81+
{ name: 'link-permission-create', url: '/permission-create', text: 'Create permission', component: PermissionCreate, isRootMenu: true },
82+
{ name: 'link-permission-list', url: '/permission-list', text: 'List permissions', component: PermissionList, isRootMenu: true },
83+
{ name: 'link-role-create', url: '/role-create', text: 'Create role', component: RoleCreate, isRootMenu: true },
84+
{ name: 'link-role-list', url: '/role-list', text: 'List role', component: RoleList, isRootMenu: true },
85+
{ name: 'link-resource-create', url: '/resource-create', text: 'Create resource', component: ResourceCreate, isRootMenu: true },
86+
{ name: 'link-resource-list', url: '/resource-list', text: 'List resource', component: ResourceList, isRootMenu: true },
8487
];
8588

8689
// let routes = [
@@ -100,7 +103,7 @@ const App = () => {
100103
<>
101104
{
102105
links.map((link, index) => {
103-
return checkPermission(link.name, userContext) && <Link key={index} to={link.url} className="list-group-item list-group-item-action bg-light">{link.text}</Link>
106+
return checkPermission(link.name, userContext) && link.isRootMenu && <Link key={index} to={link.url} className="list-group-item list-group-item-action bg-light">{link.text}</Link>
104107
})
105108
}
106109
</>

client/src/components/Permission.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ export const PermissionCreate = () => {
8080
<label><Field type="checkbox" name="isAllowed" /></label>
8181
<ErrorMessage className="col-sm-2 col-form-label text-danger" name="isAllowed" component="div" />
8282
</div>
83+
<div className="form-group row">
84+
<label htmlFor="isDisabled" className="col-sm-2 col-form-label">Is disabled</label>
85+
<label><Field type="checkbox" name="isDisabled" /></label>
86+
<ErrorMessage className="col-sm-2 col-form-label text-danger" name="isDisabled" component="div" />
87+
</div>
8388
<div className="form-group row">
8489
<label htmlFor="name" className="col-sm-2 col-form-label"></label>
8590
<button type="submit" disabled={isSubmitting}>Submit</button>
@@ -118,6 +123,7 @@ export const PermissionList = () => {
118123
<th>Resource</th>
119124
<th>Role</th>
120125
<th>Is allowed</th>
126+
<th>Is disabled</th>
121127
</tr>
122128
</thead>
123129
<tbody>
@@ -129,6 +135,7 @@ export const PermissionList = () => {
129135
<td>{resource.resourceName}</td>
130136
<td>{resource.roleName}</td>
131137
<td>{resource.isAllowed.toString()}</td>
138+
<td>{resource.isDisabled.toString()}</td>
132139
</tr>
133140
)
134141
})

client/src/components/Posts.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
22
import { Switch, Route, Link, useRouteMatch, useParams, useHistory } from "react-router-dom";
33
import { useForm } from 'react-hook-form';
44
import { useSelector, useDispatch } from 'react-redux';
5-
import { checkPermission } from "../utils/permissionManager.js";
5+
import { checkPermission, checkIsDisabled } from "../utils/permissionManager.js";
66

77
export const SecuedLink = ({ resource, text, url }) => {
88

@@ -13,8 +13,9 @@ export const SecuedLink = ({ resource, text, url }) => {
1313
console.log('SecuedLink ', resource, text, url);
1414

1515
const isAllowed = checkPermission(resource, userContext);
16+
const isDisabled = checkIsDisabled(resource, userContext);
1617

17-
return (isAllowed && <Link to={() => url}>{text}</Link>)
18+
return (isAllowed && <Link className={isDisabled ? "disable-control" : ""} to={() => url}>{text}</Link>)
1819
}
1920

2021
export const Home = () => {
@@ -199,9 +200,8 @@ export const PostSummary = (post) => {
199200
<h3>{post.title}</h3>
200201
<img src={post.imgUrl} style={{ height: "50px", width: "50px" }} alt="post img" className="pull-left thumb margin10 img-thumbnail"></img>
201202
<p>{post.emText}</p>
202-
<Link to={() => `/post-detail/${post.id}`}>Detail</Link> &nbsp;
203-
<Link to={() => `/post-edit/${post.id}`}>Edit</Link> &nbsp;
204-
{/* <Link to={() => `/post-delete/${post.id}` style={{ pointerEvents: 'none' }}}>Delete</Link> &nbsp; */}
203+
<SecuedLink resource='link-post-edit' url={`/post-detail/${post.id}`} text='Detail'></SecuedLink>&nbsp;
204+
<SecuedLink resource='link-post-edit' url={`/post-edit/${post.id}`} text='Edit'></SecuedLink>&nbsp;
205205
<SecuedLink resource='link-post-delete' url={`/post-delete/${post.id}`} text='Delete'></SecuedLink>
206206
</div>
207207
)
@@ -313,6 +313,7 @@ export const PostDetail = () => {
313313

314314
let fetchData = (id) => {
315315
dispatch({ type: "FETCH_POST_DETAIL", payload: id });
316+
dispatch({ type: "FETCH_COMMENTS", payload: id, });
316317
}
317318

318319
useEffect(() => {
@@ -323,6 +324,10 @@ export const PostDetail = () => {
323324
return state.posts.selectedPost;
324325
});
325326

327+
const comments = useSelector(state => {
328+
return state.posts.selectedComments;
329+
});
330+
326331
let match = useRouteMatch();
327332

328333
return (
@@ -331,6 +336,7 @@ export const PostDetail = () => {
331336
<h2>{post.title}</h2>
332337
<img src={post.imgUrl} style={{ height: "50px", width: "50px" }} alt="post img" className="pull-left thumb margin10 img-thumbnail"></img>
333338
<article><p>{post.articleText}</p></article>
339+
<p>Total comments {comments.length}</p>
334340
<a className="btn btn-blog pull-right marginBottom10" href={post.readMoreUrl}>READ MORE</a>
335341
</div>
336342
<div>

client/src/sagas/api.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import axios from 'axios';
22

3-
const BaseUrl = 'http://localhost:5005/api';
3+
const BaseUrl = 'http://localhost:5002/api';
44
const AuthUrl = 'http://localhost:5000';
55

66

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
1+
const getElement = (resource, userContext) => {
2+
return userContext.resources
3+
&& userContext.resources.length > 0
4+
&& userContext.resources.find(element => element.name === resource);
5+
}
6+
17
export const checkPermission = (resource, userContext) => {
28
console.log('checkPermission', resource, userContext.resources);
3-
return userContext.isAuthenticated && userContext.resources.includes(resource);
9+
const element = getElement(resource, userContext);
10+
return userContext.isAuthenticated && element != null && element.isAllowed;
11+
}
12+
13+
export const checkIsDisabled = (resource, userContext) => {
14+
console.log('isDisabled', resource, userContext.resources);
15+
const element = getElement(resource, userContext);
16+
return userContext.isAuthenticated && element != null && element.isDisabled;
417
}

server/AuthWebApplication/AuthWebApplication/AuthWebApplication.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
4-
<TargetFramework>netcoreapp3.1</TargetFramework>
4+
<TargetFramework>net5.0</TargetFramework>
55
<UserSecretsId>6b6ddae3-064a-423b-b950-8a4e0b0cb4cf</UserSecretsId>
66
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
77
</PropertyGroup>

server/AuthWebApplication/AuthWebApplication/Models/ViewModels/ApplicationPermissionViewModel.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public ApplicationPermissionViewModel(ApplicationPermission permission)
1616
this.RoleName = permission.Role.Name;
1717
this.ResourceName = permission.Resource.Name;
1818
this.IsAllowed = permission.IsAllowed.ToString();
19+
this.IsDisabled = permission.IsDisabled.ToString();
1920
}
2021

2122
public string Id { get; set; }
@@ -29,5 +30,7 @@ public ApplicationPermissionViewModel(ApplicationPermission permission)
2930
public string ResourceName { get; set; }
3031

3132
public string IsAllowed { get; set; }
33+
34+
public string IsDisabled { get; set; }
3235
}
3336
}

server/AuthWebApplication/AuthWebApplication/Utilities/Tokens.cs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,28 @@ public static async Task<object> GenerateJwt(ClaimsIdentity identity, IJwtFactor
2121
string id = identity.Claims.Single(c => c.Type == "id").Value;
2222
var name = user.FirstName + " " + user.LastName;
2323
string token = await jwtFactory.GenerateEncodedToken(user.UserName, identity);
24-
List<string> resources = new List<string>();
25-
if (roles!=null)
24+
25+
List<object> resources = new List<object>();
26+
if (roles != null)
2627
{
2728
var roleIds = roles.Select(x => (string)x.Id).ToList();
28-
var permissions = db.Permissions.Include(x => x.Resource).Where(x => roleIds.Contains(x.RoleId) && x.IsAllowed).Select(x => new { name = x.Resource.Name, isAllowed = x.IsAllowed, isDisabled = x.IsDisabled })
29+
resources = db.Permissions.Include(x => x.Resource).Where(x => roleIds.Contains(x.RoleId) && x.IsAllowed).Select(x => (dynamic) new { name = x.Resource.Name, isAllowed = x.IsAllowed, isDisabled = x.IsDisabled })
2930
.ToList();
30-
resources = permissions.Select(x => x.name).ToList();
31+
//resources = permissions.Select(x => x.name).ToList();
3132
}
32-
33-
var response = new
33+
34+
dynamic response = new
3435
{
3536
id = id,
3637
name = name,
3738
userName = user.UserName,
38-
resources = resources,
3939
roles = roles,
4040
access_token = token,
4141
expires_in = (int)jwtOptions.ValidFor.TotalSeconds,
42-
token_type = "bearer"
42+
token_type = "bearer",
43+
resources = resources
4344
};
45+
4446
return response;
4547
}
4648
}

0 commit comments

Comments
 (0)