Add logged user and user communities endpoint
This commit is contained in:
parent
ddcc591d12
commit
a85330e8cf
7 changed files with 180 additions and 3 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "tether",
|
"name": "tether",
|
||||||
"version": "0.3.3",
|
"version": "0.3.4",
|
||||||
"description": "Communication server using the Nexlink protocol",
|
"description": "Communication server using the Nexlink protocol",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@ import { type FastifyInstance } from "fastify";
|
||||||
import * as controller from "./user.js";
|
import * as controller from "./user.js";
|
||||||
|
|
||||||
const userRoutes = async (fastify: FastifyInstance) => {
|
const userRoutes = async (fastify: FastifyInstance) => {
|
||||||
|
fastify.get(`/logged`, controller.getUserLogged);
|
||||||
fastify.get(`/:id`, controller.getUser);
|
fastify.get(`/:id`, controller.getUser);
|
||||||
fastify.post(`/`, controller.postCreateUser);
|
fastify.post(`/`, controller.postCreateUser);
|
||||||
fastify.patch(`/:id`, controller.patchUser);
|
fastify.patch(`/:id`, controller.patchUser);
|
||||||
fastify.delete(`/:id`, controller.deleteUser);
|
fastify.delete(`/:id`, controller.deleteUser);
|
||||||
fastify.get(`/:id/sessions`, controller.getSessions);
|
fastify.get(`/:id/sessions`, controller.getSessions);
|
||||||
|
fastify.get(`/:id/communities`, controller.getCommunities);
|
||||||
};
|
};
|
||||||
|
|
||||||
export { userRoutes };
|
export { userRoutes };
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,13 @@
|
||||||
import type { API_ERROR } from "../errors.js";
|
import type { API_ERROR } from "../errors.js";
|
||||||
|
|
||||||
|
interface IGetLoggedUserResponseError {
|
||||||
|
error: API_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGetLoggedUserResponseSuccess {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface IGetUserParams {
|
interface IGetUserParams {
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
@ -92,7 +100,29 @@ interface IGetSessionsResponseSession {
|
||||||
userId: string;
|
userId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IGetCommunitiesParams {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGetCommunitiesResponseError {
|
||||||
|
id: string;
|
||||||
|
error: API_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGetCommunitiesResponseSuccess {
|
||||||
|
id: string;
|
||||||
|
communities: IGetCommunitiesResponseCommunity[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGetCommunitiesResponseCommunity {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
type IGetLoggedUserResponseError,
|
||||||
|
type IGetLoggedUserResponseSuccess,
|
||||||
type IGetUserParams,
|
type IGetUserParams,
|
||||||
type IGetUserResponseError,
|
type IGetUserResponseError,
|
||||||
type IGetUserResponseSuccess,
|
type IGetUserResponseSuccess,
|
||||||
|
|
@ -110,4 +140,8 @@ export {
|
||||||
type IGetSessionsResponseError,
|
type IGetSessionsResponseError,
|
||||||
type IGetSessionsResponseSuccess,
|
type IGetSessionsResponseSuccess,
|
||||||
type IGetSessionsResponseSession,
|
type IGetSessionsResponseSession,
|
||||||
|
type IGetCommunitiesParams,
|
||||||
|
type IGetCommunitiesResponseError,
|
||||||
|
type IGetCommunitiesResponseSuccess,
|
||||||
|
type IGetCommunitiesResponseCommunity,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import { type FastifyReply, type FastifyRequest } from "fastify";
|
import { type FastifyReply, type FastifyRequest } from "fastify";
|
||||||
import type {
|
import type {
|
||||||
|
IGetLoggedUserResponseError,
|
||||||
|
IGetLoggedUserResponseSuccess,
|
||||||
IGetUserParams,
|
IGetUserParams,
|
||||||
IGetUserResponseError,
|
IGetUserResponseError,
|
||||||
IGetUserResponseSuccess,
|
IGetUserResponseSuccess,
|
||||||
|
|
@ -16,6 +18,9 @@ import type {
|
||||||
IGetSessionsParams,
|
IGetSessionsParams,
|
||||||
IGetSessionsResponseError,
|
IGetSessionsResponseError,
|
||||||
IGetSessionsResponseSuccess,
|
IGetSessionsResponseSuccess,
|
||||||
|
IGetCommunitiesParams,
|
||||||
|
IGetCommunitiesResponseError,
|
||||||
|
IGetCommunitiesResponseSuccess,
|
||||||
} from "./types.js";
|
} from "./types.js";
|
||||||
import {
|
import {
|
||||||
getUserByIdAuth,
|
getUserByIdAuth,
|
||||||
|
|
@ -23,9 +28,27 @@ import {
|
||||||
getUserSessionsByIdAuth,
|
getUserSessionsByIdAuth,
|
||||||
deleteUserByIdAuth,
|
deleteUserByIdAuth,
|
||||||
createUserAuth,
|
createUserAuth,
|
||||||
|
getUserCommunitiesByIdAuth,
|
||||||
|
getLoggedUserAuth,
|
||||||
} from "../../services/user/user.js";
|
} from "../../services/user/user.js";
|
||||||
import { API_ERROR } from "../errors.js";
|
import { API_ERROR } from "../errors.js";
|
||||||
|
|
||||||
|
const getUserLogged = async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
const authHeader = request.headers["authorization"];
|
||||||
|
|
||||||
|
const user = await getLoggedUserAuth(authHeader);
|
||||||
|
if (user === API_ERROR.ACCESS_DENIED) {
|
||||||
|
reply.status(404);
|
||||||
|
return {
|
||||||
|
error: API_ERROR.ACCESS_DENIED,
|
||||||
|
} as IGetLoggedUserResponseError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: user.id,
|
||||||
|
} as IGetLoggedUserResponseSuccess;
|
||||||
|
};
|
||||||
|
|
||||||
const getUser = async (request: FastifyRequest, reply: FastifyReply) => {
|
const getUser = async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
const { id } = request.params as IGetUserParams;
|
const { id } = request.params as IGetUserParams;
|
||||||
const authHeader = request.headers["authorization"];
|
const authHeader = request.headers["authorization"];
|
||||||
|
|
@ -160,4 +183,42 @@ const getSessions = async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
} as IGetSessionsResponseSuccess;
|
} as IGetSessionsResponseSuccess;
|
||||||
};
|
};
|
||||||
|
|
||||||
export { getUser, postCreateUser, patchUser, deleteUser, getSessions };
|
const getCommunities = async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
const { id } = request.params as IGetCommunitiesParams;
|
||||||
|
const authHeader = request.headers["authorization"];
|
||||||
|
|
||||||
|
const communities = await getUserCommunitiesByIdAuth(id, authHeader);
|
||||||
|
if (!communities) {
|
||||||
|
reply.status(404);
|
||||||
|
return {
|
||||||
|
id: id,
|
||||||
|
error: API_ERROR.NOT_FOUND,
|
||||||
|
} as IGetCommunitiesResponseError;
|
||||||
|
}
|
||||||
|
if (communities === API_ERROR.ACCESS_DENIED) {
|
||||||
|
reply.status(403);
|
||||||
|
return {
|
||||||
|
id: id,
|
||||||
|
error: API_ERROR.ACCESS_DENIED,
|
||||||
|
} as IGetCommunitiesResponseError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: id,
|
||||||
|
communities: communities.map((community) => ({
|
||||||
|
id: community.id,
|
||||||
|
name: community.name,
|
||||||
|
description: community.description,
|
||||||
|
})),
|
||||||
|
} as IGetCommunitiesResponseSuccess;
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
getUserLogged,
|
||||||
|
getUser,
|
||||||
|
postCreateUser,
|
||||||
|
patchUser,
|
||||||
|
deleteUser,
|
||||||
|
getSessions,
|
||||||
|
getCommunities,
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,25 @@
|
||||||
import type { User, Session } from "../../generated/prisma/client.js";
|
import type {
|
||||||
|
User,
|
||||||
|
Session,
|
||||||
|
Community,
|
||||||
|
} from "../../generated/prisma/client.js";
|
||||||
import { getUserFromAuth, isUserOwnerOrAdmin } from "../auth/helpers.js";
|
import { getUserFromAuth, isUserOwnerOrAdmin } from "../auth/helpers.js";
|
||||||
import { getDB } from "../../store/store.js";
|
import { getDB } from "../../store/store.js";
|
||||||
import { API_ERROR } from "../../controllers/errors.js";
|
import { API_ERROR } from "../../controllers/errors.js";
|
||||||
import type { ICreateUser, IUpdateUser } from "./types.js";
|
import type { ICreateUser, IUpdateUser } from "./types.js";
|
||||||
|
|
||||||
|
const getLoggedUserAuth = async (
|
||||||
|
authHeader: string | undefined,
|
||||||
|
): Promise<User | API_ERROR.ACCESS_DENIED> => {
|
||||||
|
const authUser = await getUserFromAuth(authHeader);
|
||||||
|
|
||||||
|
if (!authUser) {
|
||||||
|
return API_ERROR.ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return authUser;
|
||||||
|
};
|
||||||
|
|
||||||
const getUserById = async (id: string): Promise<User | null> => {
|
const getUserById = async (id: string): Promise<User | null> => {
|
||||||
return await getDB().user.findUnique({
|
return await getDB().user.findUnique({
|
||||||
where: { id: id },
|
where: { id: id },
|
||||||
|
|
@ -133,7 +149,41 @@ const getUserSessionsByIdAuth = async (
|
||||||
return sessions;
|
return sessions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getUserCommunitiesById = async (
|
||||||
|
id: string,
|
||||||
|
): Promise<Community[] | null> => {
|
||||||
|
return await getDB().community.findMany({
|
||||||
|
where: {
|
||||||
|
members: {
|
||||||
|
some: {
|
||||||
|
id: id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getUserCommunitiesByIdAuth = async (
|
||||||
|
id: string,
|
||||||
|
authHeader: string | undefined,
|
||||||
|
): Promise<Community[] | null | API_ERROR.ACCESS_DENIED> => {
|
||||||
|
const authUser = await getUserFromAuth(authHeader);
|
||||||
|
const user = await getUserById(id);
|
||||||
|
const communities = await getUserCommunitiesById(id);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!(await isUserOwnerOrAdmin(authUser, {
|
||||||
|
user: user,
|
||||||
|
}))
|
||||||
|
) {
|
||||||
|
return API_ERROR.ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return communities;
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
getLoggedUserAuth,
|
||||||
getUserById,
|
getUserById,
|
||||||
getUserByIdAuth,
|
getUserByIdAuth,
|
||||||
createUser,
|
createUser,
|
||||||
|
|
@ -144,4 +194,6 @@ export {
|
||||||
deleteUserByIdAuth,
|
deleteUserByIdAuth,
|
||||||
getUserSessionsById,
|
getUserSessionsById,
|
||||||
getUserSessionsByIdAuth,
|
getUserSessionsByIdAuth,
|
||||||
|
getUserCommunitiesById,
|
||||||
|
getUserCommunitiesByIdAuth,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,12 @@ test("can register", async () => {
|
||||||
state.userId = response.id;
|
state.userId = response.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("shouldn't be authorized to get logged user", async () => {
|
||||||
|
const response = await apiGet(`user/logged`);
|
||||||
|
|
||||||
|
assert.equal(response.error, "ACCESS_DENIED");
|
||||||
|
});
|
||||||
|
|
||||||
test("shouldn't be able to login", async () => {
|
test("shouldn't be able to login", async () => {
|
||||||
const response = await apiPost(`auth/login`, {
|
const response = await apiPost(`auth/login`, {
|
||||||
username: state.username,
|
username: state.username,
|
||||||
|
|
@ -48,6 +54,12 @@ test("can login", async () => {
|
||||||
state.token = response.token;
|
state.token = response.token;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("can get logged user", async () => {
|
||||||
|
const response = await apiGet(`user/logged`, state.token);
|
||||||
|
|
||||||
|
assert.equal(response.id, state.userId);
|
||||||
|
});
|
||||||
|
|
||||||
test("shouldn't be authorized to get user", async () => {
|
test("shouldn't be authorized to get user", async () => {
|
||||||
const response1 = await apiGet(`user/${state.userId}`);
|
const response1 = await apiGet(`user/${state.userId}`);
|
||||||
assert.equal(response1.error, "ACCESS_DENIED");
|
assert.equal(response1.error, "ACCESS_DENIED");
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,22 @@ test("can accept invite", async () => {
|
||||||
assert.equal(responseGet.members.length === 2, true);
|
assert.equal(responseGet.members.length === 2, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("can get user communities", async () => {
|
||||||
|
const response = await apiGet(
|
||||||
|
`user/${state.userId2}/communities`,
|
||||||
|
state.token2,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(response.id, state.userId2);
|
||||||
|
assert.equal(response.communities.length === 1, true);
|
||||||
|
assert.equal(response.communities[0].id, state.communityId);
|
||||||
|
assert.equal(response.communities[0].name, state.communityName);
|
||||||
|
assert.equal(
|
||||||
|
response.communities[0].description,
|
||||||
|
state.communityDescription,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test("can get invite", async () => {
|
test("can get invite", async () => {
|
||||||
const response = await apiGet(`invite/${state.inviteId}`);
|
const response = await apiGet(`invite/${state.inviteId}`);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue