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

feat: edit user info page #230

Merged
merged 15 commits into from
Oct 4, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ module.exports = (plugin) => {
})
.then(() => {
ctx.response.status = 200;
ctx.response.body = {
status: "success",
};
})
.catch((err) => {
ctx.response.status = 400;
ctx.response.body = {
status: "error",
message: err.message,
};
});
};

Expand Down
45 changes: 44 additions & 1 deletion publish-backend/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ module.exports = {
},
},
});
event.params.data.role = invitedUser.role.id;
if (invitedUser) {
event.params.data.role = invitedUser.role.id;
}
},
async afterCreate(event) {
const { email } = event.result;
Expand All @@ -57,6 +59,47 @@ module.exports = {
},
});
},
async beforeUpdate(event) {
const { id } = event.params.where;
const { email: newEmail } = event.params.data;
const { email: oldEmail } = await strapi.entityService.findOne(
"plugin::users-permissions.user",
id
);
event.state = {
oldEmail,
newEmail,
};
},
async afterUpdate(event) {
const { oldEmail, newEmail } = event.state;
if (oldEmail !== newEmail) {
await strapi.db.query("api::invited-user.invited-user").update({
where: {
email: {
$eq: oldEmail,
},
},
data: {
email: newEmail,
},
});
}
},
async beforeDelete(event) {
const { id } = event.params.where;
const { email } = await strapi.entityService.findOne(
"plugin::users-permissions.user",
id
);
await strapi.db.query("api::invited-user.invited-user").delete({
where: {
email: {
$eq: email,
},
},
});
},
});
},
};
2 changes: 2 additions & 0 deletions publish-backend/src/seed/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ async function createSeedUsers(strapi) {
data: {
username: "contributor-user",
name: "contributor-user",
slug: "contributor-user",
email: "[email protected]",
password: "contributor",
provider: "local",
Expand All @@ -43,6 +44,7 @@ async function createSeedUsers(strapi) {
data: {
username: "editor-user",
name: "editor-user",
slug: "editor-user",
email: "[email protected]",
password: "editor",
provider: "local",
Expand Down
40 changes: 39 additions & 1 deletion publish-frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion publish-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"react-icons": "^4.10.1",
"slugify": "^1.6.6",
"tiptap-markdown": "^0.8.2",
"uuid": "^9.0.1"
"uuid": "^9.0.1",
"yup": "^1.3.2"
},
"devDependencies": {
"eslint": "^8.46.0",
Expand Down
7 changes: 6 additions & 1 deletion publish-frontend/src/components/nav-menu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { signOut } from 'next-auth/react';
import NextLink from 'next/link';

import { isEditor } from '@/lib/current-user';

Expand Down Expand Up @@ -145,7 +146,11 @@ const NavMenuContent = ({ user, onClose, ...rest }) => {
</Flex>
</MenuButton>
<MenuList>
<MenuItem icon={<Icon icon={faUser} fixedWidth />}>
<MenuItem
icon={<Icon icon={faUser} fixedWidth />}
as={NextLink}
href={`/users/${user.id}`}
>
Your Profile
</MenuItem>
<MenuItem
Expand Down
78 changes: 78 additions & 0 deletions publish-frontend/src/lib/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,26 @@ export async function getMe(token) {
return res.json();
}

export async function updateMe(token, data) {
const endpoint = `${api_root}/users/me`;

const options = {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`
},
body: JSON.stringify(data)
};

const res = await fetch(endpoint, options);

if (!res.ok) {
throw new Error('updateUsers Failed');
}
return res.json();
}

export async function getUsers(token) {
const endpoint = `${api_root}/users?populate=*`;

Expand Down Expand Up @@ -58,3 +78,61 @@ export async function userExists(token, email) {
const data = await res.json();
return data.length > 0;
}

export async function getUser(token, userId) {
const endpoint = `${api_root}/users/${userId}?populate=role`;

const options = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`
}
};

const res = await fetch(endpoint, options);

if (!res.ok) {
throw new Error('getUsers Failed');
}
return res.json();
}

export async function updateUser(token, userId, data) {
const endpoint = `${api_root}/users/${userId}`;

const options = {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`
},
body: JSON.stringify(data)
};

const res = await fetch(endpoint, options);

if (!res.ok) {
throw new Error('updateUsers Failed');
}
return res.json();
}

export async function deleteUser(token, userId) {
const endpoint = `${api_root}/users/${userId}`;

const options = {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`
}
};

const res = await fetch(endpoint, options);

if (!res.ok) {
throw new Error('deleteUsers Failed');
}
return res.json();
}
42 changes: 37 additions & 5 deletions publish-frontend/src/middleware.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,43 @@
import { withAuth } from 'next-auth/middleware';
import { NextResponse } from 'next/server';
import { NextResponse, URLPattern } from 'next/server';

const PATTERNS = [
[
new URLPattern({ pathname: '/users/:id' }),
({ pathname }) => pathname.groups
]
];

const params = url => {
const input = url.split('?')[0];
let result = {};

for (const [pattern, handler] of PATTERNS) {
const patternResult = pattern.exec(input);
if (patternResult !== null && 'pathname' in patternResult) {
result = handler(patternResult);
break;
}
}
return result;
};

export default withAuth(req => {
if (
req.nextUrl.pathname.startsWith('/tags') ||
req.nextUrl.pathname.startsWith('/users')
) {
if (req.nextUrl.pathname.startsWith('/users')) {
const { id } = params(req.url);
if (req.nextauth.token.userRole !== 'Editor') {
if (id !== undefined) {
if (req.nextauth.token.id != id) {
return NextResponse.redirect(new URL('/posts', req.url));
}
} else {
return NextResponse.redirect(new URL('/posts', req.url));
}
}
}
if (req.nextUrl.pathname.startsWith('/tags')) {
const { id } = params(req.url);
console.log('id', id);
if (req.nextauth.token.userRole !== 'Editor') {
return NextResponse.redirect(new URL('/posts', req.url));
}
Expand Down
Loading
Loading