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

97 user role crud #100

Merged
merged 6 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions react-admin/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import PageEdit from "./pages/page/PageEdit";
import AdminUserTable from "./pages/admin-user/AdminUserTable";
import AdminUserCreate from "./pages/admin-user/AdminUserCreate";
import AdminUserEdit from "./pages/admin-user/AdminUserEdit";
import RoleTable from "./pages/role/RoleTable";
import RoleCreate from "./pages/role/RoleCreate";
import RoleEdit from "./pages/role/RoleEdit";


function App() {
return (
Expand All @@ -22,6 +26,10 @@ function App() {

<Route element={<AppLayout />}>
<Route path="/admin" element={<Dashboard />} />
<Route path="/admin/role" element={<RoleTable />} />
<Route path="/admin/role-create" element={<RoleCreate />} />
<Route path="/admin/role-edit/:role_id" element={<RoleEdit />} />

<Route path="/admin/page" element={<PageTable />} />
<Route path="/admin/page-create" element={<PageCreate />} />
<Route path="/admin/page-edit/:page_id" element={<PageEdit />} />
Expand Down
18 changes: 10 additions & 8 deletions react-admin/src/components/InputField.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React from "react";

const InputField = ({
label,
type = "text",
name,
value,
onChange,
autoFocus,
label,
type = "text",
name,
value,
onChange,
autoFocus,
placeholder,
required
}) => {
return (
<div>
Expand All @@ -17,12 +19,12 @@ const InputField = ({
<input
type={type}
name={name}
required
required={required}
value={value}
onChange={onChange}
autoFocus={autoFocus}
className="appearance-none rounded-md ring-1 ring-primary-300 relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-primary-500 sm:text-sm focus:z-10"
placeholder={label}
placeholder={placeholder ?? label}
/>
</div>
</div>
Expand Down
11 changes: 11 additions & 0 deletions react-admin/src/layouts/partials/AppSidebar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ function AppSidebar() {
</a>
)}
</Menu.Item>
<Menu.Item as="li">
{({active}) => (
<a href="/admin/role"
className={`flex items-center w-full py-1 px-2 rounded relative hover:text-white hover:bg-gray-700`}
>
<div>
Role
</div>
</a>
)}
</Menu.Item>
<Menu.Item>
{({ active }) => (
<a
Expand Down
71 changes: 71 additions & 0 deletions react-admin/src/pages/role/RoleCreate.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {useState} from "react";
import {Link, redirect, useNavigate} from "react-router-dom";
import axios from "axios";

function RoleCreate() {
const [name, setName] = useState('Editor');
const [identifier, setIdentifier] = useState('editor');
const navigate = useNavigate()

const handleSubmit = (async (e) => {
e.preventDefault()

const created_page_response = await axios({
url: 'http://localhost:8080/api/role',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + localStorage.getItem("AUTH_TOKEN"),
},
data: JSON.stringify({name: name, identifier: identifier, permissions: []})
})
if (created_page_response.status) {
return navigate("/admin/role");
}
})

return (
<div className="flex-1 bg-white">
<div className="px-5 pl-64 ">
<div className="w-full">
<div className="block rounded-lg p-6">
<h1 className="text-xl font-semibold mb-4 text-gray-900 dark:text-gray-100">
Role Information
</h1>
{/*<p className="text-gray-600 dark:text-gray-300 mb-6">Use a permanent address where you can*/}
{/* receive mail.</p>*/}
<form onSubmit={handleSubmit}>
<div className="mb-4">
<input type="text" placeholder="Name"
value={name}
onChange={e => setName(e.target.value)}
className="border p-2 rounded w-full"/>
</div>
<div className="mb-4">
<input type="text"
placeholder="Identifier"
value={identifier}
onChange={e => setIdentifier(e.target.value)}
className="border p-2 rounded w-full"/>
</div>
<div className="flex items-center">
<button type="submit"
className="bg-primary-600 py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
>
Save
</button>
<Link to="/admin/page"
className="ml-auto font-medium text-gray-600 hover:text-gray-500">
Cancel
</Link>
</div>

</form>
</div>
</div>
</div>
</div>
)
}

export default RoleCreate
103 changes: 103 additions & 0 deletions react-admin/src/pages/role/RoleEdit.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import {useEffect, useState} from "react";
import {Link, redirect, useNavigate, useParams} from "react-router-dom";
import {isEmpty} from "lodash";
import axios from "axios";

function RoleEdit() {
const [name, setName] = useState('Contact US update');
const [identifier, setIdentifier] = useState('contact-us-update');
const navigate = useNavigate()
const params = useParams();


useEffect(() => {
const mounted = (async () => {
const response = await axios({
url: 'http://localhost:8080/api/role/' + params.role_id,
method: 'get',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + localStorage.getItem("AUTH_TOKEN"),
}
})

if (!response.status) {
return
}

return response.data
})

mounted().then((res) => {
if (isEmpty(res)) {
localStorage. removeItem("AUTH_TOKEN")
return navigate("/admin/login")
}

setName(res.role_model.name)
setIdentifier(res.role_model.identifier)
})

}, [])

const handleSubmit = (async (e) => {
e.preventDefault()
const updated_role_response = await axios({
url: 'http://localhost:8080/api/role/' + params.role_id,
method: 'put',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + localStorage.getItem("AUTH_TOKEN"),
},
data: JSON.stringify({name: name, identifier: identifier, permissions: []})
})
if (updated_role_response.status) {
return navigate("/admin/role");
}
})

return (
<div className="flex-1 bg-white">
<div className="px-5 pl-64">
<div className="w-full">
<div className="block rounded-lg p-6">
<h1 className="text-xl font-semibold mb-4 text-gray-900 dark:text-gray-100">
Role Information
</h1>
{/*<p className="text-gray-600 dark:text-gray-300 mb-6">Use a permanent address where you can*/}
{/* receive mail.</p>*/}
<form onSubmit={handleSubmit}>
<div className="mb-4">
<input type="text" placeholder="Name"
value={name}
onChange={e => setName(e.target.value)}
className="border p-2 rounded w-full"/>
</div>
<div className="mb-4">
<input type="text"
placeholder="Identifier"
value={identifier}
onChange={e => setIdentifier(e.target.value)}
className="border p-2 rounded w-full"/>
</div>
<div className="flex items-center">
<button type="submit"
className="bg-primary-600 py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
>
Save
</button>
<Link to="/admin/role"
className="ml-auto font-medium text-gray-600 hover:text-gray-500">
Cancel
</Link>
</div>

</form>
</div>
</div>
</div>
</div>
)
}

export default RoleEdit
102 changes: 102 additions & 0 deletions react-admin/src/pages/role/RoleTable.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import {useEffect, useState} from "react";
import {Link, redirect, useNavigate} from "react-router-dom";
import {isEmpty} from "lodash";
import axios from "axios";

function RoleTable() {
const [roles, setRoles] = useState([]);
const navigate = useNavigate()

const getFormattedDate = ((date) => {
var date = new Date(date);

return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
})

useEffect(() => {
const mounted = (async () => {

const response = await axios({
url: 'http://localhost:8080/api/role',
method: 'get',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + localStorage.getItem("AUTH_TOKEN"),
}
})
return response
})

mounted().then(({data}) => {
console.log(data)
if (isEmpty(data)) {
localStorage.removeItem("AUTH_TOKEN")
return navigate("/admin/login")
}
setRoles(data.data)
})

}, [])

return (
<div className="flex-1 bg-white">
<div className="px-5 ml-64">
<div className="flex items-center">
<div className="p-5 text-2xl font-semibold text-primary-500">
Roles
</div>
<Link className="ml-auto bg-primary-600 py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
to="/admin/role-create">
Create
</Link>
</div>


<div className="overflow-x-hidden">
<table className="min-w-full bg-white shadow-md rounded">
<thead>
<tr className="bg-gray-700 text-white">
<th className="py-3 px-4 rounded-l font-semibold text-left">ID</th>
<th className="py-3 px-4 font-semibol text-left">Name</th>
<th className="py-3 px-4 font-semibol text-left">Identifier</th>
<th className="py-3 px-4 font-semibol text-left">Created at</th>
<th className="py-3 px-4 font-semibol text-left">Updated at</th>
<th className="py-3 px-4 font-semibol text-left">Created by</th>
<th className="py-3 px-4 font-semibol text-left">Updated by</th>
<th className="py-3 px-4 rounded-r font-semibol text-left">Action</th>
</tr>
</thead>
<tbody className="">
{roles.map((role) => {
return (
<tr key={role.id} className="border-b">
<td className="py-3 px-4">{role.id}</td>
<td className="py-3 px-4">{role.name}</td>
<td className="py-3 px-4">{role.identifier}</td>
<td className="py-3 px-4">
{getFormattedDate(role.created_at)}
</td>
<td className="py-3 px-4">
{getFormattedDate(role.updated_at)}
</td>
<td className="py-3 px-4">{role.created_by}</td>
<td className="py-3 px-4">{role.updated_by}</td>
<td className="py-3 px-4">
<Link className="font-medium text-primary-600 hover:text-primary-800"
to={`/admin/role-edit/${role.id}`}>
Edit
</Link>

</td>
</tr>
)
})}
</tbody>
</table>
</div>
</div>
</div>
)
}

export default RoleTable
1 change: 1 addition & 0 deletions src/api/rest_api/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ pub mod health_check_api_handler;
pub mod component_all_api_handler;
pub mod admin_user;
pub mod page;
pub mod role;

34 changes: 34 additions & 0 deletions src/api/rest_api/handlers/role/fetch_role_api_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use std::sync::Arc;

use crate::models::role_model::RoleModel;
use crate::{
avored_state::AvoRedState, error::Result
};

use axum::{extract::{Path as AxumPath, State}, Json, response::IntoResponse};
use serde::Serialize;

pub async fn fetch_role_api_handler(
AxumPath(role_id): AxumPath<String>,
state: State<Arc<AvoRedState>>
) -> Result<impl IntoResponse> {
println!("->> {:<12} - fetch_role_api_handler", "HANDLER");

let role_model = state
.role_service
.find_by_id(&state.db, role_id)
.await?;
let response = FetchPageResponse {
status: true,
role_model: role_model

Check warning

Code scanning / clippy

redundant field names in struct initialization Warning

redundant field names in struct initialization
};

Ok(Json(response))
}


#[derive(Serialize, Debug)]
pub struct FetchPageResponse {
pub status: bool,
pub role_model: RoleModel
}
Loading
Loading